Overview | Package | Class | Source | Class tree | Glossary | Deus Ex UnrealScript Documentation |
previous class next class | frames no frames |
00001 00002 00003 00004 00005 00006 00007 00008 00009 00010 00011 00012 00013 00014 00015 00016 00017 00018 00019 00020 00021 00022 00023 00024 00025 00026 00027 00028 00029 00030 00031 00032 00033 00034 00035 00036 00037 00038 00039 00040 00041 00042 00043 00044 00045 00046 00047 00048 00049 00050 00051 00052 00053 00054 00055 00056 00057 00058 00059 00060 00061 00062 00063 00064 00065 00066 00067 00068 00069 00070 00071 00072 00073 00074 00075 00076 00077 00078 00079 00080 00081 00082 00083 00084 00085 00086 00087 00088 00089 00090 00091 00092 00093 00094 00095 00096 00097 00098 00099 00100 00101 00102 00103 00104 00105 00106 00107 00108 00109 00110 00111 00112 00113 00114 00115 00116 00117 00118 00119 00120 00121 00122 00123 00124 00125 00126 00127 00128 00129 00130 00131 00132 00133 00134 00135 00136 00137 00138 00139 00140 00141 00142 00143 00144 00145 00146 00147 00148 00149 00150 00151 00152 00153 00154 00155 00156 00157 00158 00159 00160 00161 00162 00163 00164 00165 00166 00167 00168 00169 00170 00171 00172 00173 00174 00175 00176 00177 00178 00179 00180 00181 00182 00183 00184 00185 00186 00187 00188 00189 00190 00191 00192 00193 00194 00195 00196 00197 00198 00199 00200 00201 00202 00203 00204 00205 00206 00207 00208 00209 00210 00211 00212 00213 00214 00215 00216 00217 00218 00219 00220 00221 00222 00223 00224 00225 00226 00227 00228 00229 00230 00231 00232 00233 00234 00235 00236 00237 00238 00239 00240 00241 00242 00243 00244 00245 00246 00247 00248 00249 00250 00251 00252 00253 00254 00255 00256 00257 00258 00259 00260 00261 00262 00263 00264 00265 00266 00267 00268 00269 00270 00271 00272 00273 00274 00275 00276 00277 00278 00279 00280 00281 00282 00283 00284 00285 00286 00287 00288 00289 00290 00291 00292 00293 00294 00295 00296 00297 00298 00299 00300 00301 00302 00303 00304 00305 00306 00307 00308 00309 00310 00311 00312 00313 00314 00315 00316 00317 00318 00319 00320 00321 00322 00323 00324 00325 00326 00327 00328 00329 00330 00331 00332 00333 00334 00335 00336 00337 00338 00339 00340 00341 00342 00343 00344 00345 00346 00347 00348 00349 00350 00351 00352 00353 00354 00355 00356 00357 00358 00359 00360 00361 00362 00363 00364 00365 00366 00367 00368 00369 00370 00371 00372 00373 00374 00375 00376 00377 00378 00379 00380 00381 00382 00383 00384 00385 00386 00387 00388 00389 00390 00391 00392 00393 00394 00395 00396 00397 00398 00399 00400 00401 00402 00403 00404 00405 00406 00407 00408 00409 00410 00411 00412 00413 00414 00415 00416 00417 00418 00419 00420 00421 00422 00423 00424 00425 00426 00427 00428 00429 00430 00431 00432 00433 00434 00435 00436 00437 00438 00439 00440 00441 00442 00443 00444 00445 00446 00447 00448 00449 00450 00451 00452 00453 00454 00455 00456 00457 00458 00459 00460 00461 00462 00463 00464 00465 00466 00467 00468 00469 00470 00471 00472 00473 00474 00475 00476 00477 00478 00479 00480 00481 00482 00483 00484 00485 00486 00487 00488 00489 00490 00491 00492 00493 00494 00495 00496 00497 00498 00499 00500 00501 00502 00503 00504 00505 00506 00507 00508 00509 00510 00511 00512 00513 00514 00515 00516 00517 00518 00519 00520 00521 00522 00523 00524 00525 00526 00527 00528 00529 00530 00531 00532 00533 00534 00535 00536 00537 00538 00539 00540 00541 00542 00543 00544 00545 00546 00547 00548 00549 00550 00551 00552 00553 00554 00555 00556 00557 00558 00559 00560 00561 00562 00563 00564 00565 00566 00567 00568 00569 00570 00571 00572 00573 00574 00575 00576 00577 00578 00579 00580 00581 00582 00583 00584 00585 00586 00587 00588 00589 00590 00591 00592 00593 00594 00595 00596 00597 00598 00599 00600 00601 00602 00603 00604 00605 00606 00607 00608 00609 00610 00611 00612 00613 00614 00615 00616 00617 00618 00619 00620 00621 00622 00623 00624 00625 00626 00627 00628 00629 00630 00631 00632 00633 00634 00635 00636 00637 00638 00639 00640 00641 00642 00643 00644 00645 00646 00647 00648 00649 00650 00651 00652 00653 00654 00655 00656 00657 00658 00659 00660 00661 00662 00663 00664 00665 00666 00667 00668 00669 00670 00671 00672 00673 00674 00675 00676 00677 00678 00679 00680 00681 00682 00683 00684 00685 00686 00687 00688 00689 00690 00691 00692 00693 00694 00695 00696 00697 00698 00699 00700 00701 00702 00703 00704 00705 00706 00707 00708 00709 00710 00711 00712 00713 00714 00715 00716 00717 00718 00719 00720 00721 00722 00723 00724 00725 00726 00727 00728 00729 00730 00731 00732 00733 00734 00735 00736 00737 00738 00739 00740 00741 00742 00743 00744 00745 00746 00747 00748 00749 00750 00751 00752 00753 00754 00755 00756 00757 00758 00759 00760 00761 00762 00763 00764 00765 00766 00767 00768 00769 00770 00771 00772 00773 00774 00775 00776 00777 00778 00779 00780 00781 00782 00783 00784 00785 00786 00787 00788 00789 00790 00791 00792 00793 00794 00795 00796 00797 00798 00799 00800 00801 00802 00803 00804 00805 00806 00807 00808 00809 00810 00811 00812 00813 00814 00815 00816 00817 00818 00819 00820 00821 00822 00823 00824 00825 00826 00827 00828 00829 00830 00831 00832 00833 00834 00835 00836 00837 00838 00839 00840 00841 00842 00843 00844 00845 00846 00847 00848 00849 00850 00851 00852 00853 00854 00855 00856 00857 00858 00859 00860 00861 00862 00863 00864 00865 00866 00867 00868 00869 00870 00871 00872 00873 00874 00875 00876 00877 00878 00879 00880 00881 00882 00883 00884 00885 00886 00887 00888 00889 00890 00891 00892 00893 00894 00895 00896 00897 00898 00899 00900 00901 00902 00903 00904 00905 00906 00907 00908 00909 00910 00911 00912 00913 00914 00915 00916 00917 00918 00919 00920 00921 00922 00923 00924 00925 00926 00927 00928 00929 00930 00931 00932 00933 00934 00935 00936 00937 00938 00939 00940 00941 00942 00943 00944 00945 00946 00947 00948 00949 00950 00951 00952 00953 00954 00955 00956 00957 00958 00959 00960 00961 00962 00963 00964 00965 00966 00967 00968 00969 00970 00971 00972 00973 00974 00975 00976 00977 00978 00979 00980 00981 00982 00983 00984 00985 00986 00987 00988 00989 00990 00991 00992 00993 00994 00995 00996 00997 00998 00999 01000 01001 01002 01003 01004 01005 01006 01007 01008 01009 01010 01011 01012 01013 01014 01015 01016 01017 01018 01019 01020 01021 01022 01023 01024 01025 01026 01027 01028 01029 01030 01031 01032 01033 01034 01035 01036 01037 01038 01039 01040 01041 01042 01043 01044 01045 01046 01047 01048 01049 01050 01051 01052 01053 01054 01055 01056 01057 01058 01059 01060 01061 01062 01063 01064 01065 01066 01067 01068 01069 01070 01071 01072 01073 01074 01075 01076 01077 01078 01079 01080 01081 01082 01083 01084 01085 01086 01087 01088 01089 01090 01091 01092 01093 01094 01095 01096 01097 01098 01099 01100 01101 01102 01103 01104 01105 01106 01107 01108 01109 01110 01111 01112 01113 01114 01115 01116 01117 01118 01119 01120 01121 01122 01123 01124 01125 01126 01127 01128 01129 01130 01131 01132 01133 01134 01135 01136 01137 01138 01139 01140 01141 01142 01143 01144 01145 01146 01147 01148 01149 01150 01151 01152 01153 01154 01155 01156 01157 01158 01159 01160 01161 01162 01163 01164 01165 01166 01167 01168 01169 01170 01171 01172 01173 01174 01175 01176 01177 01178 01179 01180 01181 01182 01183 01184 01185 01186 01187 01188 01189 01190 01191 01192 01193 01194 01195 01196 01197 01198 01199 01200 01201 01202 01203 01204 01205 01206 01207 01208 01209 01210 01211 01212 01213 01214 01215 01216 01217 01218 01219 01220 01221 01222 01223 01224 01225 01226 01227 01228 01229 01230 01231 01232 01233 01234 01235 01236 01237 01238 01239 01240 01241 01242 01243 01244 01245 01246 01247 01248 01249 01250 01251 01252 01253 01254 01255 01256 01257 01258 01259 01260 01261 01262 01263 01264 01265 01266 01267 01268 01269 01270 01271 01272 01273 01274 01275 01276 01277 01278 01279 01280 01281 01282 01283 01284 01285 01286 01287 01288 01289 01290 01291 01292 01293 01294 01295 01296 01297 01298 01299 01300 01301 01302 01303 01304 01305 01306 01307 01308 01309 01310 01311 01312 01313 01314 01315 01316 01317 01318 01319 01320 01321 01322 01323 01324 01325 01326 01327 01328 01329 01330 01331 01332 01333 01334 01335 01336 01337 01338 01339 01340 01341 01342 01343 01344 01345 01346 01347 01348 01349 01350 01351 01352 01353 01354 01355 01356 01357 01358 01359 01360 01361 01362 01363 01364 01365 01366 01367 01368 01369 01370 01371 01372 01373 01374 01375 01376 01377 01378 01379 01380 01381 01382 01383 01384 01385 01386 01387 01388 01389 01390 01391 01392 01393 01394 01395 01396 01397 01398 01399 01400 01401 01402 01403 01404 01405 01406 01407 01408 01409 01410 01411 01412 01413 01414 01415 01416 01417 01418 01419 01420 01421 01422 01423 01424 01425 01426 01427 01428 01429 01430 01431 01432 01433 01434 01435 01436 01437 01438 01439 01440 01441 01442 01443 01444 01445 01446 01447 01448 01449 01450 01451 01452 01453 01454 01455 01456 01457 01458 01459 01460 01461 01462 01463 01464 01465 01466 01467 01468 01469 01470 01471 01472 01473 01474 01475 01476 01477 01478 01479 01480 01481 01482 01483 01484 01485 01486 01487 01488 01489 01490 01491 01492 01493 01494 01495 01496 01497 01498 01499 01500 01501 01502 01503 01504 01505 01506 01507 01508 01509 01510 01511 01512 01513 01514 01515 01516 01517 01518 01519 01520 01521 01522 01523 01524 01525 01526 01527 01528 01529 01530 01531 01532 01533 01534 01535 01536 01537 01538 01539 01540 01541 01542 01543 01544 01545 01546 01547 01548 01549 01550 01551 01552 01553 01554 01555 01556 01557 01558 01559 01560 01561 01562 01563 01564 01565 01566 01567 01568 01569 01570 01571 01572 01573 01574 01575 01576 01577 01578 01579 01580 01581 01582 01583 01584 01585 01586 01587 01588 01589 01590 01591 01592 01593 01594 01595 01596 01597 01598 01599 01600 01601 01602 01603 01604 01605 01606 01607 01608 01609 01610 01611 01612 01613 01614 01615 01616 01617 01618 01619 01620 01621 01622 01623 01624 01625 01626 01627 01628 01629 01630 01631 01632 01633 01634 01635 01636 01637 01638 01639 01640 01641 01642 01643 01644 01645 01646 01647 01648 01649 01650 01651 01652 01653 01654 01655 01656 01657 01658 01659 01660 01661 01662 01663 01664 01665 01666 01667 01668 01669 01670 01671 01672 01673 01674 01675 01676 01677 01678 01679 01680 01681 01682 01683 01684 01685 01686 01687 01688 01689 01690 01691 01692 01693 01694 01695 01696 01697 01698 01699 01700 01701 01702 01703 01704 01705 01706 01707 01708 01709 01710 01711 01712 01713 01714 01715 01716 01717 01718 01719 01720 01721 01722 01723 01724 01725 01726 01727 01728 01729 01730 01731 01732 01733 01734 01735 01736 01737 01738 01739 01740 01741 01742 01743 01744 01745 01746 01747 01748 01749 01750 01751 01752 01753 01754 01755 01756 01757 01758 01759 01760 01761 01762 01763 01764 01765 01766 01767 01768 01769 01770 01771 01772 01773 01774 01775 01776 01777 01778 01779 01780 01781 01782 01783 01784 01785 01786 01787 01788 01789 01790 01791 01792 01793 01794 01795 01796 01797 01798 01799 01800 01801 01802 01803 01804 01805 01806 01807 01808 01809 01810 01811 01812 01813 01814 01815 01816 01817 01818 01819 01820 01821 01822 01823 01824 01825 01826 01827 01828 01829 01830 01831 01832 01833 01834 01835 01836 01837 01838 01839 01840 01841 01842 01843 01844 01845 01846 01847 01848 01849 01850 01851 01852 01853 01854 01855 01856 01857 01858 01859 01860 01861 01862 01863 01864 01865 01866 01867 01868 01869 01870 01871 01872 01873 01874 01875 01876 01877 01878 01879 01880 01881 01882 01883 01884 01885 01886 01887 01888 01889 01890 01891 01892 01893 01894 01895 01896 01897 01898 01899 01900 01901 01902 01903 01904 01905 01906 01907 01908 01909 01910 01911 01912 01913 01914 01915 01916 01917 01918 01919 01920 01921 01922 01923 01924 01925 01926 01927 01928 01929 01930 01931 01932 01933 01934 01935 01936 01937 01938 01939 01940 01941 01942 01943 01944 01945 01946 01947 01948 01949 01950 01951 01952 01953 01954 01955 01956 01957 01958 01959 01960 01961 01962 01963 01964 01965 01966 01967 01968 01969 01970 01971 01972 01973 01974 01975 01976 01977 01978 01979 01980 01981 01982 01983 01984 01985 01986 01987 01988 01989 01990 01991 01992 01993 01994 01995 01996 01997 01998 01999 02000 02001 02002 02003 02004 02005 02006 02007 02008 02009 02010 02011 02012 02013 02014 02015 02016 02017 02018 02019 02020 02021 02022 02023 02024 02025 02026 02027 02028 02029 02030 02031 02032 02033 02034 02035 02036 02037 02038 02039 02040 02041 02042 02043 02044 02045 02046 02047 02048 02049 02050 02051 02052 02053 02054 02055 02056 02057 02058 02059 02060 02061 02062 02063 02064 02065 02066 02067 02068 02069 02070 02071 02072 02073 02074 02075 02076 02077 02078 02079 02080 02081 02082 02083 02084 02085 02086 02087 02088 02089 02090 02091 02092 02093 02094 02095 02096 02097 02098 02099 02100 02101 02102 02103 02104 02105 02106 02107 02108 02109 02110 02111 02112 02113 02114 02115 02116 02117 02118 02119 02120 02121 02122 02123 02124 02125 02126 02127 02128 02129 02130 02131 02132 02133 02134 02135 02136 02137 02138 02139 02140 02141 02142 02143 02144 02145 02146 02147 02148 02149 02150 02151 02152 02153 02154 02155 02156 02157 02158 02159 02160 02161 02162 02163 02164 02165 02166 02167 02168 02169 02170 02171 02172 02173 02174 02175 02176 02177 02178 02179 02180 02181 02182 02183 02184 02185 02186 02187 02188 02189 02190 02191 02192 02193 02194 02195 02196 02197 02198 02199 02200 02201 02202 02203 02204 02205 02206 02207 02208 02209 02210 02211 02212 02213 02214 02215 02216 02217 02218 02219 02220 02221 02222 02223 02224 02225 02226 02227 02228 02229 02230 02231 02232 02233 02234 02235 02236 02237 02238 02239 02240 02241 02242 02243 02244 02245 02246 02247 02248 02249 02250 02251 02252 02253 02254 02255 02256 02257 02258 02259 02260 02261 02262 02263 02264 02265 02266 02267 02268 02269 02270 02271 02272 02273 02274 02275 02276 02277 02278 02279 02280 02281 02282 02283 02284 02285 02286 02287 02288 02289 02290 02291 02292 02293 02294 02295 02296 02297 02298 02299 02300 02301 02302 02303 02304 02305 02306 02307 02308 02309 02310 02311 02312 02313 02314 02315 02316 02317 02318 02319 02320 02321 02322 02323 02324 02325 02326 02327 02328 02329 02330 02331 02332 02333 02334 02335 02336 02337 02338 02339 02340 02341 02342 02343 02344 02345 02346 02347 02348 02349 02350 02351 02352 02353 02354 02355 02356 02357 02358 02359 02360 02361 02362 02363 02364 02365 02366 02367 02368 02369 02370 02371 02372 02373 02374 02375 02376 02377 02378 02379 02380 02381 02382 02383 02384 02385 02386 02387 02388 02389 02390 02391 02392 02393 02394 02395 02396 02397 02398 02399 02400 02401 02402 02403 02404 02405 02406 02407 02408 02409 02410 02411 02412 02413 02414 02415 02416 02417 02418 02419 02420 02421 02422 02423 02424 02425 02426 02427 02428 02429 02430 02431 02432 02433 02434 02435 02436 02437 02438 02439 02440 02441 02442 02443 02444 02445 02446 02447 02448 02449 02450 02451 02452 02453 02454 02455 02456 02457 02458 02459 02460 02461 02462 02463 02464 02465 02466 02467 02468 02469 02470 02471 02472 02473 02474 02475 02476 02477 02478 02479 02480 02481 02482 02483 02484 02485 02486 02487 02488 02489 02490 02491 02492 02493 02494 02495 02496 02497 02498 02499 02500 02501 02502 02503 02504 02505 02506 02507 02508 02509 02510 02511 02512 02513 02514 02515 02516 02517 02518 02519 02520 02521 02522 02523 02524 02525 02526 02527 02528 02529 02530 02531 02532 02533 02534 02535 02536 02537 02538 02539 02540 02541 02542 02543 02544 02545 02546 02547 02548 02549 02550 02551 02552 02553 02554 02555 02556 02557 02558 02559 02560 02561 02562 02563 02564 02565 02566 02567 02568 02569 02570 02571 02572 02573 02574 02575 02576 02577 02578 02579 02580 02581 02582 02583 02584 02585 02586 02587 02588 02589 02590 02591 02592 02593 02594 02595 02596 02597 02598 02599 02600 02601 02602 02603 02604 02605 02606 02607 02608 02609 02610 02611 02612 02613 02614 02615 02616 02617 02618 02619 02620 02621 02622 02623 02624 02625 02626 02627 02628 02629 02630 02631 02632 02633 02634 02635 02636 02637 02638 02639 02640 02641 02642 02643 02644 02645 02646 02647 02648 02649 02650 02651 02652 02653 02654 02655 02656 02657 02658 02659 02660 02661 02662 02663 02664 02665 02666 02667 02668 02669 02670 02671 02672 02673 02674 02675 02676 02677 02678 02679 02680 02681 02682 02683 02684 02685 02686 02687 02688 02689 02690 02691 02692 02693 02694 02695 02696 02697 02698 02699 02700 02701 02702 02703 02704 02705 02706 02707 02708 02709 02710 02711 02712 02713 02714 02715 02716 02717 02718 02719 02720 02721 02722 02723 02724 02725 02726 02727 02728 02729 02730 02731 02732 02733 02734 02735 02736 02737 02738 02739 02740 02741 02742 02743 02744 02745 02746 02747 02748 02749 02750 02751 02752 02753 02754 02755 02756 02757 02758 02759 02760 02761 02762 02763 02764 02765 02766 02767 02768 02769 02770 02771 02772 02773 02774 02775 02776 02777 02778 02779 02780 02781 02782 02783 02784 02785 02786 02787 02788 02789 02790 02791 02792 02793 02794 02795 02796 02797 02798 02799 02800 02801 02802 02803 02804 02805 02806 02807 02808 02809 02810 02811 02812 02813 02814 02815 02816 02817 02818 02819 02820 02821 02822 02823 02824 02825 02826 02827 02828 02829 02830 02831 02832 02833 02834 02835 02836 02837 02838 02839 02840 02841 02842 02843 02844 02845 02846 02847 02848 02849 02850 02851 02852 02853 02854 02855 02856 02857 02858 02859 02860 02861 02862 02863 02864 02865 02866 02867 02868 02869 02870 02871 02872 02873 02874 02875 02876 02877 02878 02879 02880 02881 02882 02883 02884 02885 02886 02887 02888 02889 02890 02891 02892 02893 02894 02895 02896 02897 02898 02899 02900 02901 02902 02903 02904 02905 02906 02907 02908 02909 02910 02911 02912 02913 02914 02915 02916 02917 02918 02919 02920 02921 02922 02923 02924 02925 02926 02927 02928 02929 02930 02931 02932 02933 02934 02935 02936 02937 02938 02939 02940 02941 02942 02943 02944 02945 02946 02947 02948 02949 02950 02951 02952 02953 02954 02955 02956 02957 02958 02959 02960 02961 02962 02963 02964 02965 02966 02967 02968 02969 02970 02971 02972 02973 02974 02975 02976 02977 02978 02979 02980 02981 02982 02983 02984 02985 02986 02987 02988 02989 02990 02991 02992 02993 02994 02995 02996 02997 02998 02999 03000 03001 03002 03003 03004 03005 03006 03007 03008 03009 03010 03011 03012 03013 03014 03015 03016 03017 03018 03019 03020 03021 03022 03023 03024 03025 03026 03027 03028 03029 03030 03031 03032 03033 03034 03035 03036 03037 03038 03039 03040 03041 03042 03043 03044 03045 03046 03047 03048 03049 03050 03051 03052 03053 03054 03055 03056 03057 03058 03059 03060 03061 03062 03063 03064 03065 03066 03067 03068 03069 03070 03071 03072 03073 03074 03075 03076 03077 03078 03079 03080 03081 03082 03083 03084 03085 03086 03087 03088 03089 03090 03091 03092 03093 03094 03095 03096 03097 03098 03099 03100 03101 03102 03103 03104 03105 03106 03107 03108 03109 03110 03111 03112 03113 03114 03115 03116 03117 03118 03119 03120 03121 03122 03123 03124 03125 03126 03127 03128 03129 03130 03131 03132 03133 03134 03135 03136 03137 03138 03139 03140 03141 03142 03143 03144 03145 03146 03147 03148 03149 03150 03151 03152 03153 03154 03155 03156 03157 03158 03159 03160 03161 03162 03163 03164 03165 03166 03167 03168 03169 03170 03171 03172 03173 03174 03175 03176 03177 03178 03179 03180 03181 03182 03183 03184 03185 03186 03187 03188 03189 03190 03191 03192 03193 03194 03195 03196 03197 03198 03199 03200 03201 03202 03203 03204 03205 03206 03207 03208 03209 03210 03211 03212 03213 03214 03215 03216 03217 03218 03219 03220 03221 03222 03223 03224 03225 03226 03227 03228 03229 03230 03231 03232 03233 03234 03235 03236 03237 03238 03239 03240 03241 03242 03243 03244 03245 03246 03247 03248 03249 03250 03251 03252 03253 03254 03255 03256 03257 03258 03259 03260 03261 03262 03263 03264 03265 03266 03267 03268 03269 03270 03271 03272 03273 03274 03275 03276 03277 03278 03279 03280 03281 03282 03283 03284 03285 03286 03287 03288 03289 03290 03291 03292 03293 03294 03295 03296 03297 03298 03299 03300 03301 03302 03303 03304 03305 03306 03307 03308 03309 03310 03311 03312 03313 03314 03315 03316 03317 03318 03319 03320 03321 03322 03323 03324 03325 03326 03327 03328 03329 03330 03331 03332 03333 03334 03335 03336 03337 03338 03339 03340 03341 03342 03343 03344 03345 03346 03347 03348 03349 03350 03351 03352 03353 03354 03355 03356 03357 03358 03359 03360 03361 03362 03363 03364 03365 03366 03367 03368 03369 03370 03371 03372 03373 03374 03375 03376 03377 03378 03379 03380 03381 03382 03383 03384 03385 03386 03387 03388 03389 03390 03391 03392 03393 03394 03395 03396 03397 03398 03399 03400 03401 03402 03403 03404 03405 03406 03407 03408 03409 03410 03411 03412 03413 03414 03415 03416 03417 03418 03419 03420 03421 03422 03423 03424 03425 03426 03427 03428 03429 03430 03431 03432 03433 03434 03435 03436 03437 03438 03439 03440 03441 03442 03443 03444 03445 03446 03447 03448 03449 03450 03451 03452 03453 03454 03455 03456 03457 03458 03459 03460 03461 03462 03463 03464 03465 03466 03467 03468 03469 03470 03471 03472 03473 03474 03475 03476 03477 03478 03479 03480 03481 03482 03483 03484 03485 03486 03487 03488 03489 03490 03491 03492 03493 03494 03495 03496 03497 03498 03499 03500 03501 03502 03503 03504 03505 03506 03507 03508 03509 03510 03511 03512 03513 03514 03515 03516 03517 03518 03519 03520 03521 03522 03523 03524 03525 03526 03527 03528 03529 03530 03531 03532 03533 03534 03535 03536 03537 03538 03539 03540 03541 03542 03543 03544 03545 03546 03547 03548 03549 03550 03551 03552 03553 03554 03555 03556 03557 03558 03559 03560 03561 03562 03563 03564 03565 03566 03567 03568 03569 03570 03571 03572 03573 03574 03575 03576 03577 03578 03579 03580 03581 03582 03583 03584 03585 03586 03587 03588 03589 03590 03591 03592 03593 03594 03595 03596 03597 03598 03599 03600 03601 03602 03603 03604 03605 03606 03607 03608 03609 03610 03611 03612 03613 03614 03615 03616 03617 03618 03619 03620 03621 03622 03623 03624 03625 03626 03627 03628 03629 03630 03631 03632 03633 03634 03635 03636 03637 03638 03639 03640 03641 03642 03643 03644 03645 03646 03647 03648 03649 03650 03651 03652 03653 03654 03655 03656 03657 03658 03659 03660 03661 03662 03663 03664 03665 03666 03667 03668 03669 03670 03671 03672 03673 03674 03675 03676 03677 03678 03679 03680 03681 03682 03683 03684 03685 03686 03687 03688 03689 03690 03691 03692 03693 03694 03695 03696 03697 03698 03699 03700 03701 03702 03703 03704 03705 03706 03707 03708 03709 03710 03711 03712 03713 03714 03715 03716 03717 03718 03719 03720 03721 03722 03723 03724 03725 03726 03727 03728 03729 03730 03731 03732 03733 03734 03735 03736 03737 03738 03739 03740 03741 03742 03743 03744 03745 03746 03747 03748 03749 03750 03751 03752 03753 03754 03755 03756 03757 03758 03759 03760 03761 03762 03763 03764 03765 03766 03767 03768 03769 03770 03771 03772 03773 03774 03775 03776 03777 03778 03779 03780 03781 03782 03783 03784 03785 03786 03787 03788 03789 03790 03791 03792 03793 03794 03795 03796 03797 03798 03799 03800 03801 03802 03803 03804 03805 03806 03807 03808 03809 03810 03811 03812 03813 03814 03815 03816 03817 03818 03819 03820 03821 03822 03823 03824 03825 03826 03827 03828 03829 03830 03831 03832 03833 03834 03835 03836 03837 03838 03839 03840 03841 03842 03843 03844 03845 03846 03847 03848 03849 03850 03851 03852 03853 03854 03855 03856 03857 03858 03859 03860 03861 03862 03863 03864 03865 03866 03867 03868 03869 03870 03871 03872 03873 03874 03875 03876 03877 03878 03879 03880 03881 03882 03883 03884 03885 03886 03887 03888 03889 03890 03891 03892 03893 03894 03895 03896 03897 03898 03899 03900 03901 03902 03903 03904 03905 03906 03907 03908 03909 03910 03911 03912 03913 03914 03915 03916 03917 03918 03919 03920 03921 03922 03923 03924 03925 03926 03927 03928 03929 03930 03931 03932 03933 03934 03935 03936 03937 03938 03939 03940 03941 03942 03943 03944 03945 03946 03947 03948 03949 03950 03951 03952 03953 03954 03955 03956 03957 03958 03959 03960 03961 03962 03963 03964 03965 03966 03967 03968 03969 03970 03971 03972 03973 03974 03975 03976 03977 03978 03979 03980 03981 03982 03983 03984 03985 03986 03987 03988 03989 03990 03991 03992 03993 03994 03995 03996 03997 03998 03999 04000 04001 04002 04003 04004 04005 04006 04007 04008 04009 04010 04011 04012 04013 04014 04015 04016 04017 04018 04019 04020 04021 04022 04023 04024 04025 04026 04027 04028 04029 04030 04031 04032 04033 04034 04035 04036 04037 04038 04039 04040 04041 04042 04043 04044 04045 04046 04047 04048 04049 04050 04051 04052 04053 04054 04055 04056 04057 04058 04059 04060 04061 04062 04063 04064 04065 04066 04067 04068 04069 04070 04071 04072 04073 04074 04075 04076 04077 04078 04079 04080 04081 04082 04083 04084 04085 04086 04087 04088 04089 04090 04091 04092 04093 04094 04095 04096 04097 04098 04099 04100 04101 04102 04103 04104 04105 04106 04107 04108 04109 04110 04111 04112 04113 04114 04115 04116 04117 04118 04119 04120 04121 04122 04123 04124 04125 04126 04127 04128 04129 04130 04131 04132 04133 04134 04135 04136 04137 04138 04139 04140 04141 04142 04143 04144 04145 04146 04147 04148 04149 04150 04151 04152 04153 04154 04155 04156 04157 04158 04159 04160 04161 04162 04163 04164 04165 04166 04167 04168 04169 04170 04171 04172 04173 04174 04175 04176 04177 04178 04179 04180 04181 04182 04183 04184 04185 04186 04187 04188 04189 04190 04191 04192 04193 04194 04195 04196 04197 04198 04199 04200 04201 04202 04203 04204 04205 04206 04207 04208 04209 04210 04211 04212 04213 04214 04215 04216 04217 04218 04219 04220 04221 04222 04223 04224 04225 04226 04227 04228 04229 04230 04231 04232 04233 04234 04235 04236 04237 04238 04239 04240 04241 04242 04243 04244 04245 04246 04247 04248 04249 04250 04251 04252 04253 04254 04255 04256 04257 04258 04259 04260 04261 04262 04263 04264 04265 04266 04267 04268 04269 04270 04271 04272 04273 04274 04275 04276 04277 04278 04279 04280 04281 04282 04283 04284 04285 04286 04287 04288 04289 04290 04291 04292 04293 04294 04295 04296 04297 04298 04299 04300 04301 04302 04303 04304 04305 04306 04307 04308 04309 04310 04311 04312 04313 04314 04315 04316 04317 04318 04319 04320 04321 04322 04323 04324 04325 04326 04327 04328 04329 04330 04331 04332 04333 04334 04335 04336 04337 04338 04339 04340 04341 04342 04343 04344 04345 04346 04347 04348 04349 04350 04351 04352 04353 04354 04355 04356 04357 04358 04359 04360 04361 04362 04363 04364 04365 04366 04367 04368 04369 04370 04371 04372 04373 04374 04375 04376 04377 04378 04379 04380 04381 04382 04383 04384 04385 04386 04387 04388 04389 04390 04391 04392 04393 04394 04395 04396 04397 04398 04399 04400 04401 04402 04403 04404 04405 04406 04407 04408 04409 04410 04411 04412 04413 04414 04415 04416 04417 04418 04419 04420 04421 04422 04423 04424 04425 04426 04427 04428 04429 04430 04431 04432 04433 04434 04435 04436 04437 04438 04439 04440 04441 04442 04443 04444 04445 04446 04447 04448 04449 04450 04451 04452 04453 04454 04455 04456 04457 04458 04459 04460 04461 04462 04463 04464 04465 04466 04467 04468 04469 04470 04471 04472 04473 04474 04475 04476 04477 04478 04479 04480 04481 04482 04483 04484 04485 04486 04487 04488 04489 04490 04491 04492 04493 04494 04495 04496 04497 04498 04499 04500 04501 04502 04503 04504 04505 04506 04507 04508 04509 04510 04511 04512 04513 04514 04515 04516 04517 04518 04519 04520 04521 04522 04523 04524 04525 04526 04527 04528 04529 04530 04531 04532 04533 04534 04535 04536 04537 04538 04539 04540 04541 04542 04543 04544 04545 04546 04547 04548 04549 04550 04551 04552 04553 04554 04555 04556 04557 04558 04559 04560 04561 04562 04563 04564 04565 04566 04567 04568 04569 04570 04571 04572 04573 04574 04575 04576 04577 04578 04579 04580 04581 04582 04583 04584 04585 04586 04587 04588 04589 04590 04591 04592 04593 04594 04595 04596 04597 04598 04599 04600 04601 04602 04603 04604 04605 04606 04607 04608 04609 04610 04611 04612 04613 04614 04615 04616 04617 04618 04619 04620 04621 04622 04623 04624 04625 04626 04627 04628 04629 04630 04631 04632 04633 04634 04635 04636 04637 04638 04639 04640 04641 04642 04643 04644 04645 04646 04647 04648 04649 04650 04651 04652 04653 04654 04655 04656 04657 04658 04659 04660 04661 04662 04663 04664 04665 04666 04667 04668 04669 04670 04671 04672 04673 04674 04675 04676 04677 04678 04679 04680 04681 04682 04683 04684 04685 04686 04687 04688 04689 04690 04691 04692 04693 04694 04695 04696 04697 04698 04699 04700 04701 04702 04703 04704 04705 04706 04707 04708 04709 04710 04711 04712 04713 04714 04715 04716 04717 04718 04719 04720 04721 04722 04723 04724 04725 04726 04727 04728 04729 04730 04731 04732 04733 04734 04735 04736 04737 04738 04739 04740 04741 04742 04743 04744 04745 04746 04747 04748 04749 04750 04751 04752 04753 04754 04755 04756 04757 04758 04759 04760 04761 04762 04763 04764 04765 04766 04767 04768 04769 04770 04771 04772 04773 04774 04775 04776 04777 04778 04779 04780 04781 04782 04783 04784 04785 04786 04787 04788 04789 04790 04791 04792 04793 04794 04795 04796 04797 04798 04799 04800 04801 04802 04803 04804 04805 04806 04807 04808 04809 04810 04811 04812 04813 04814 04815 04816 04817 04818 04819 04820 04821 04822 04823 04824 04825 04826 04827 04828 04829 04830 04831 04832 04833 04834 04835 04836 04837 04838 04839 04840 04841 04842 04843 04844 04845 04846 04847 04848 04849 04850 04851 04852 04853 04854 04855 04856 04857 04858 04859 04860 04861 04862 04863 04864 04865 04866 04867 04868 04869 04870 04871 04872 04873 04874 04875 04876 04877 04878 04879 04880 04881 04882 04883 04884 04885 04886 04887 04888 04889 04890 04891 04892 04893 04894 04895 04896 04897 04898 04899 04900 04901 04902 04903 04904 04905 04906 04907 04908 04909 04910 04911 04912 04913 04914 04915 04916 04917 04918 04919 04920 04921 04922 04923 04924 04925 04926 04927 04928 04929 04930 04931 04932 04933 04934 04935 04936 04937 04938 04939 04940 04941 04942 04943 04944 04945 04946 04947 04948 04949 04950 04951 04952 04953 04954 04955 04956 04957 04958 04959 04960 04961 04962 04963 04964 04965 04966 04967 04968 04969 04970 04971 04972 04973 04974 04975 04976 04977 04978 04979 04980 04981 04982 04983 04984 04985 04986 04987 04988 04989 04990 04991 04992 04993 04994 04995 04996 04997 04998 04999 05000 05001 05002 05003 05004 05005 05006 05007 05008 05009 05010 05011 05012 05013 05014 05015 05016 05017 05018 05019 05020 05021 05022 05023 05024 05025 05026 05027 05028 05029 05030 05031 05032 05033 05034 05035 05036 05037 05038 05039 05040 05041 05042 05043 05044 05045 05046 05047 05048 05049 05050 05051 05052 05053 05054 05055 05056 05057 05058 05059 05060 05061 05062 05063 05064 05065 05066 05067 05068 05069 05070 05071 05072 05073 05074 05075 05076 05077 05078 05079 05080 05081 05082 05083 05084 05085 05086 05087 05088 05089 05090 05091 05092 05093 05094 05095 05096 05097 05098 05099 05100 05101 05102 05103 05104 05105 05106 05107 05108 05109 05110 05111 05112 05113 05114 05115 05116 05117 05118 05119 05120 05121 05122 05123 05124 05125 05126 05127 05128 05129 05130 05131 05132 05133 05134 05135 05136 05137 05138 05139 05140 05141 05142 05143 05144 05145 05146 05147 05148 05149 05150 05151 05152 05153 05154 05155 05156 05157 05158 05159 05160 05161 05162 05163 05164 05165 05166 05167 05168 05169 05170 05171 05172 05173 05174 05175 05176 05177 05178 05179 05180 05181 05182 05183 05184 05185 05186 05187 05188 05189 05190 05191 05192 05193 05194 05195 05196 05197 05198 05199 05200 05201 05202 05203 05204 05205 05206 05207 05208 05209 05210 05211 05212 05213 05214 05215 05216 05217 05218 05219 05220 05221 05222 05223 05224 05225 05226 05227 05228 05229 05230 05231 05232 05233 05234 05235 05236 05237 05238 05239 05240 05241 05242 05243 05244 05245 05246 05247 05248 05249 05250 05251 05252 05253 05254 05255 05256 05257 05258 05259 05260 05261 05262 05263 05264 05265 05266 05267 05268 05269 05270 05271 05272 05273 05274 05275 05276 05277 05278 05279 05280 05281 05282 05283 05284 05285 05286 05287 05288 05289 05290 05291 05292 05293 05294 05295 05296 05297 05298 05299 05300 05301 05302 05303 05304 05305 05306 05307 05308 05309 05310 05311 05312 05313 05314 05315 05316 05317 05318 05319 05320 05321 05322 05323 05324 05325 05326 05327 05328 05329 05330 05331 05332 05333 05334 05335 05336 05337 05338 05339 05340 05341 05342 05343 05344 05345 05346 05347 05348 05349 05350 05351 05352 05353 05354 05355 05356 05357 05358 05359 05360 05361 05362 05363 05364 05365 05366 05367 05368 05369 05370 05371 05372 05373 05374 05375 05376 05377 05378 05379 05380 05381 05382 05383 05384 05385 05386 05387 05388 05389 05390 05391 05392 05393 05394 05395 05396 05397 05398 05399 05400 05401 05402 05403 05404 05405 05406 05407 05408 05409 05410 05411 05412 05413 05414 05415 05416 05417 05418 05419 05420 05421 05422 05423 05424 05425 05426 05427 05428 05429 05430 05431 05432 05433 05434 05435 05436 05437 05438 05439 05440 05441 05442 05443 05444 05445 05446 05447 05448 05449 05450 05451 05452 05453 05454 05455 05456 05457 05458 05459 05460 05461 05462 05463 05464 05465 05466 05467 05468 05469 05470 05471 05472 05473 05474 05475 05476 05477 05478 05479 05480 05481 05482 05483 05484 05485 05486 05487 05488 05489 05490 05491 05492 05493 05494 05495 05496 05497 05498 05499 05500 05501 05502 05503 05504 05505 05506 05507 05508 05509 05510 05511 05512 05513 05514 05515 05516 05517 05518 05519 05520 05521 05522 05523 05524 05525 05526 05527 05528 05529 05530 05531 05532 05533 05534 05535 05536 05537 05538 05539 05540 05541 05542 05543 05544 05545 05546 05547 05548 05549 05550 05551 05552 05553 05554 05555 05556 05557 05558 05559 05560 05561 05562 05563 05564 05565 05566 05567 05568 05569 05570 05571 05572 05573 05574 05575 05576 05577 05578 05579 05580 05581 05582 05583 05584 05585 05586 05587 05588 05589 05590 05591 05592 05593 05594 05595 05596 05597 05598 05599 05600 05601 05602 05603 05604 05605 05606 05607 05608 05609 05610 05611 05612 05613 05614 05615 05616 05617 05618 05619 05620 05621 05622 05623 05624 05625 05626 05627 05628 05629 05630 05631 05632 05633 05634 05635 05636 05637 05638 05639 05640 05641 05642 05643 05644 05645 05646 05647 05648 05649 05650 05651 05652 05653 05654 05655 05656 05657 05658 05659 05660 05661 05662 05663 05664 05665 05666 05667 05668 05669 05670 05671 05672 05673 05674 05675 05676 05677 05678 05679 05680 05681 05682 05683 05684 05685 05686 05687 05688 05689 05690 05691 05692 05693 05694 05695 05696 05697 05698 05699 05700 05701 05702 05703 05704 05705 05706 05707 05708 05709 05710 05711 05712 05713 05714 05715 05716 05717 05718 05719 05720 05721 05722 05723 05724 05725 05726 05727 05728 05729 05730 05731 05732 05733 05734 05735 05736 05737 05738 05739 05740 05741 05742 05743 05744 05745 05746 05747 05748 05749 05750 05751 05752 05753 05754 05755 05756 05757 05758 05759 05760 05761 05762 05763 05764 05765 05766 05767 05768 05769 05770 05771 05772 05773 05774 05775 05776 05777 05778 05779 05780 05781 05782 05783 05784 05785 05786 05787 05788 05789 05790 05791 05792 05793 05794 05795 05796 05797 05798 05799 05800 05801 05802 05803 05804 05805 05806 05807 05808 05809 05810 05811 05812 05813 05814 05815 05816 05817 05818 05819 05820 05821 05822 05823 05824 05825 05826 05827 05828 05829 05830 05831 05832 05833 05834 05835 05836 05837 05838 05839 05840 05841 05842 05843 05844 05845 05846 05847 05848 05849 05850 05851 05852 05853 05854 05855 05856 05857 05858 05859 05860 05861 05862 05863 05864 05865 05866 05867 05868 05869 05870 05871 05872 05873 05874 05875 05876 05877 05878 05879 05880 05881 05882 05883 05884 05885 05886 05887 05888 05889 05890 05891 05892 05893 05894 05895 05896 05897 05898 05899 05900 05901 05902 05903 05904 05905 05906 05907 05908 05909 05910 05911 05912 05913 05914 05915 05916 05917 05918 05919 05920 05921 05922 05923 05924 05925 05926 05927 05928 05929 05930 05931 05932 05933 05934 05935 05936 05937 05938 05939 05940 05941 05942 05943 05944 05945 05946 05947 05948 05949 05950 05951 05952 05953 05954 05955 05956 05957 05958 05959 05960 05961 05962 05963 05964 05965 05966 05967 05968 05969 05970 05971 05972 05973 05974 05975 05976 05977 05978 05979 05980 05981 05982 05983 05984 05985 05986 05987 05988 05989 05990 05991 05992 05993 05994 05995 05996 05997 05998 05999 06000 06001 06002 06003 06004 06005 06006 06007 06008 06009 06010 06011 06012 06013 06014 06015 06016 06017 06018 06019 06020 06021 06022 06023 06024 06025 06026 06027 06028 06029 06030 06031 06032 06033 06034 06035 06036 06037 06038 06039 06040 06041 06042 06043 06044 06045 06046 06047 06048 06049 06050 06051 06052 06053 06054 06055 06056 06057 06058 06059 06060 06061 06062 06063 06064 06065 06066 06067 06068 06069 06070 06071 06072 06073 06074 06075 06076 06077 06078 06079 06080 06081 06082 06083 06084 06085 06086 06087 06088 06089 06090 06091 06092 06093 06094 06095 06096 06097 06098 06099 06100 06101 06102 06103 06104 06105 06106 06107 06108 06109 06110 06111 06112 06113 06114 06115 06116 06117 06118 06119 06120 06121 06122 06123 06124 06125 06126 06127 06128 06129 06130 06131 06132 06133 06134 06135 06136 06137 06138 06139 06140 06141 06142 06143 06144 06145 06146 06147 06148 06149 06150 06151 06152 06153 06154 06155 06156 06157 06158 06159 06160 06161 06162 06163 06164 06165 06166 06167 06168 06169 06170 06171 06172 06173 06174 06175 06176 06177 06178 06179 06180 06181 06182 06183 06184 06185 06186 06187 06188 06189 06190 06191 06192 06193 06194 06195 06196 06197 06198 06199 06200 06201 06202 06203 06204 06205 06206 06207 06208 06209 06210 06211 06212 06213 06214 06215 06216 06217 06218 06219 06220 06221 06222 06223 06224 06225 06226 06227 06228 06229 06230 06231 06232 06233 06234 06235 06236 06237 06238 06239 06240 06241 06242 06243 06244 06245 06246 06247 06248 06249 06250 06251 06252 06253 06254 06255 06256 06257 06258 06259 06260 06261 06262 06263 06264 06265 06266 06267 06268 06269 06270 06271 06272 06273 06274 06275 06276 06277 06278 06279 06280 06281 06282 06283 06284 06285 06286 06287 06288 06289 06290 06291 06292 06293 06294 06295 06296 06297 06298 06299 06300 06301 06302 06303 06304 06305 06306 06307 06308 06309 06310 06311 06312 06313 06314 06315 06316 06317 06318 06319 06320 06321 06322 06323 06324 06325 06326 06327 06328 06329 06330 06331 06332 06333 06334 06335 06336 06337 06338 06339 06340 06341 06342 06343 06344 06345 06346 06347 06348 06349 06350 06351 06352 06353 06354 06355 06356 06357 06358 06359 06360 06361 06362 06363 06364 06365 06366 06367 06368 06369 06370 06371 06372 06373 06374 06375 06376 06377 06378 06379 06380 06381 06382 06383 06384 06385 06386 06387 06388 06389 06390 06391 06392 06393 06394 06395 06396 06397 06398 06399 06400 06401 06402 06403 06404 06405 06406 06407 06408 06409 06410 06411 06412 06413 06414 06415 06416 06417 06418 06419 06420 06421 06422 06423 06424 06425 06426 06427 06428 06429 06430 06431 06432 06433 06434 06435 06436 06437 06438 06439 06440 06441 06442 06443 06444 06445 06446 06447 06448 06449 06450 06451 06452 06453 06454 06455 06456 06457 06458 06459 06460 06461 06462 06463 06464 06465 06466 06467 06468 06469 06470 06471 06472 06473 06474 06475 06476 06477 06478 06479 06480 06481 06482 06483 06484 06485 06486 06487 06488 06489 06490 06491 06492 06493 06494 06495 06496 06497 06498 06499 06500 06501 06502 06503 06504 06505 06506 06507 06508 06509 06510 06511 06512 06513 06514 06515 06516 06517 06518 06519 06520 06521 06522 06523 06524 06525 06526 06527 06528 06529 06530 06531 06532 06533 06534 06535 06536 06537 06538 06539 06540 06541 06542 06543 06544 06545 06546 06547 06548 06549 06550 06551 06552 06553 06554 06555 06556 06557 06558 06559 06560 06561 06562 06563 06564 06565 06566 06567 06568 06569 06570 06571 06572 06573 06574 06575 06576 06577 06578 06579 06580 06581 06582 06583 06584 06585 06586 06587 06588 06589 06590 06591 06592 06593 06594 06595 06596 06597 06598 06599 06600 06601 06602 06603 06604 06605 06606 06607 06608 06609 06610 06611 06612 06613 06614 06615 06616 06617 06618 06619 06620 06621 06622 06623 06624 06625 06626 06627 06628 06629 06630 06631 06632 06633 06634 06635 06636 06637 06638 06639 06640 06641 06642 06643 06644 06645 06646 06647 06648 06649 06650 06651 06652 06653 06654 06655 06656 06657 06658 06659 06660 06661 06662 06663 06664 06665 06666 06667 06668 06669 06670 06671 06672 06673 06674 06675 06676 06677 06678 06679 06680 06681 06682 06683 06684 06685 06686 06687 06688 06689 06690 06691 06692 06693 06694 06695 06696 06697 06698 06699 06700 06701 06702 06703 06704 06705 06706 06707 06708 06709 06710 06711 06712 06713 06714 06715 06716 06717 06718 06719 06720 06721 06722 06723 06724 06725 06726 06727 06728 06729 06730 06731 06732 06733 06734 06735 06736 06737 06738 06739 06740 06741 06742 06743 06744 06745 06746 06747 06748 06749 06750 06751 06752 06753 06754 06755 06756 06757 06758 06759 06760 06761 06762 06763 06764 06765 06766 06767 06768 06769 06770 06771 06772 06773 06774 06775 06776 06777 06778 06779 06780 06781 06782 06783 06784 06785 06786 06787 06788 06789 06790 06791 06792 06793 06794 06795 06796 06797 06798 06799 06800 06801 06802 06803 06804 06805 06806 06807 06808 06809 06810 06811 06812 06813 06814 06815 06816 06817 06818 06819 06820 06821 06822 06823 06824 06825 06826 06827 06828 06829 06830 06831 06832 06833 06834 06835 06836 06837 06838 06839 06840 06841 06842 06843 06844 06845 06846 06847 06848 06849 06850 06851 06852 06853 06854 06855 06856 06857 06858 06859 06860 06861 06862 06863 06864 06865 06866 06867 06868 06869 06870 06871 06872 06873 06874 06875 06876 06877 06878 06879 06880 06881 06882 06883 06884 06885 06886 06887 06888 06889 06890 06891 06892 06893 06894 06895 06896 06897 06898 06899 06900 06901 06902 06903 06904 06905 06906 06907 06908 06909 06910 06911 06912 06913 06914 06915 06916 06917 06918 06919 06920 06921 06922 06923 06924 06925 06926 06927 06928 06929 06930 06931 06932 06933 06934 06935 06936 06937 06938 06939 06940 06941 06942 06943 06944 06945 06946 06947 06948 06949 06950 06951 06952 06953 06954 06955 06956 06957 06958 06959 06960 06961 06962 06963 06964 06965 06966 06967 06968 06969 06970 06971 06972 06973 06974 06975 06976 06977 06978 06979 06980 06981 06982 06983 06984 06985 06986 06987 06988 06989 06990 06991 06992 06993 06994 06995 06996 06997 06998 06999 07000 07001 07002 07003 07004 07005 07006 07007 07008 07009 07010 07011 07012 07013 07014 07015 07016 07017 07018 07019 07020 07021 07022 07023 07024 07025 07026 07027 07028 07029 07030 07031 07032 07033 07034 07035 07036 07037 07038 07039 07040 07041 07042 07043 07044 07045 07046 07047 07048 07049 07050 07051 07052 07053 07054 07055 07056 07057 07058 07059 07060 07061 07062 07063 07064 07065 07066 07067 07068 07069 07070 07071 07072 07073 07074 07075 07076 07077 07078 07079 07080 07081 07082 07083 07084 07085 07086 07087 07088 07089 07090 07091 07092 07093 07094 07095 07096 07097 07098 07099 07100 07101 07102 07103 07104 07105 07106 07107 07108 07109 07110 07111 07112 07113 07114 07115 07116 07117 07118 07119 07120 07121 07122 07123 07124 07125 07126 07127 07128 07129 07130 07131 07132 07133 07134 07135 07136 07137 07138 07139 07140 07141 07142 07143 07144 07145 07146 07147 07148 07149 07150 07151 07152 07153 07154 07155 07156 07157 07158 07159 07160 07161 07162 07163 07164 07165 07166 07167 07168 07169 07170 07171 07172 07173 07174 07175 07176 07177 07178 07179 07180 07181 07182 07183 07184 07185 07186 07187 07188 07189 07190 07191 07192 07193 07194 07195 07196 07197 07198 07199 07200 07201 07202 07203 07204 07205 07206 07207 07208 07209 07210 07211 07212 07213 07214 07215 07216 07217 07218 07219 07220 07221 07222 07223 07224 07225 07226 07227 07228 07229 07230 07231 07232 07233 07234 07235 07236 07237 07238 07239 07240 07241 07242 07243 07244 07245 07246 07247 07248 07249 07250 07251 07252 07253 07254 07255 07256 07257 07258 07259 07260 07261 07262 07263 07264 07265 07266 07267 07268 07269 07270 07271 07272 07273 07274 07275 07276 07277 07278 07279 07280 07281 07282 07283 07284 07285 07286 07287 07288 07289 07290 07291 07292 07293 07294 07295 07296 07297 07298 07299 07300 07301 07302 07303 07304 07305 07306 07307 07308 07309 07310 07311 07312 07313 07314 07315 07316 07317 07318 07319 07320 07321 07322 07323 07324 07325 07326 07327 07328 07329 07330 07331 07332 07333 07334 07335 07336 07337 07338 07339 07340 07341 07342 07343 07344 07345 07346 07347 07348 07349 07350 07351 07352 07353 07354 07355 07356 07357 07358 07359 07360 07361 07362 07363 07364 07365 07366 07367 07368 07369 07370 07371 07372 07373 07374 07375 07376 07377 07378 07379 07380 07381 07382 07383 07384 07385 07386 07387 07388 07389 07390 07391 07392 07393 07394 07395 07396 07397 07398 07399 07400 07401 07402 07403 07404 07405 07406 07407 07408 07409 07410 07411 07412 07413 07414 07415 07416 07417 07418 07419 07420 07421 07422 07423 07424 07425 07426 07427 07428 07429 07430 07431 07432 07433 07434 07435 07436 07437 07438 07439 07440 07441 07442 07443 07444 07445 07446 07447 07448 07449 07450 07451 07452 07453 07454 07455 07456 07457 07458 07459 07460 07461 07462 07463 07464 07465 07466 07467 07468 07469 07470 07471 07472 07473 07474 07475 07476 07477 07478 07479 07480 07481 07482 07483 07484 07485 07486 07487 07488 07489 07490 07491 07492 07493 07494 07495 07496 07497 07498 07499 07500 07501 07502 07503 07504 07505 07506 07507 07508 07509 07510 07511 07512 07513 07514 07515 07516 07517 07518 07519 07520 07521 07522 07523 07524 07525 07526 07527 07528 07529 07530 07531 07532 07533 07534 07535 07536 07537 07538 07539 07540 07541 07542 07543 07544 07545 07546 07547 07548 07549 07550 07551 07552 07553 07554 07555 07556 07557 07558 07559 07560 07561 07562 07563 07564 07565 07566 07567 07568 07569 07570 07571 07572 07573 07574 07575 07576 07577 07578 07579 07580 07581 07582 07583 07584 07585 07586 07587 07588 07589 07590 07591 07592 07593 07594 07595 07596 07597 07598 07599 07600 07601 07602 07603 07604 07605 07606 07607 07608 07609 07610 07611 07612 07613 07614 07615 07616 07617 07618 07619 07620 07621 07622 07623 07624 07625 07626 07627 07628 07629 07630 07631 07632 07633 07634 07635 07636 07637 07638 07639 07640 07641 07642 07643 07644 07645 07646 07647 07648 07649 07650 07651 07652 07653 07654 07655 07656 07657 07658 07659 07660 07661 07662 07663 07664 07665 07666 07667 07668 07669 07670 07671 07672 07673 07674 07675 07676 07677 07678 07679 07680 07681 07682 07683 07684 07685 07686 07687 07688 07689 07690 07691 07692 07693 07694 07695 07696 07697 07698 07699 07700 07701 07702 07703 07704 07705 07706 07707 07708 07709 07710 07711 07712 07713 07714 07715 07716 07717 07718 07719 07720 07721 07722 07723 07724 07725 07726 07727 07728 07729 07730 07731 07732 07733 07734 07735 07736 07737 07738 07739 07740 07741 07742 07743 07744 07745 07746 07747 07748 07749 07750 07751 07752 07753 07754 07755 07756 07757 07758 07759 07760 07761 07762 07763 07764 07765 07766 07767 07768 07769 07770 07771 07772 07773 07774 07775 07776 07777 07778 07779 07780 07781 07782 07783 07784 07785 07786 07787 07788 07789 07790 07791 07792 07793 07794 07795 07796 07797 07798 07799 07800 07801 07802 07803 07804 07805 07806 07807 07808 07809 07810 07811 07812 07813 07814 07815 07816 07817 07818 07819 07820 07821 07822 07823 07824 07825 07826 07827 07828 07829 07830 07831 07832 07833 07834 07835 07836 07837 07838 07839 07840 07841 07842 07843 07844 07845 07846 07847 07848 07849 07850 07851 07852 07853 07854 07855 07856 07857 07858 07859 07860 07861 07862 07863 07864 07865 07866 07867 07868 07869 07870 07871 07872 07873 07874 07875 07876 07877 07878 07879 07880 07881 07882 07883 07884 07885 07886 07887 07888 07889 07890 07891 07892 07893 07894 07895 07896 07897 07898 07899 07900 07901 07902 07903 07904 07905 07906 07907 07908 07909 07910 07911 07912 07913 07914 07915 07916 07917 07918 07919 07920 07921 07922 07923 07924 07925 07926 07927 07928 07929 07930 07931 07932 07933 07934 07935 07936 07937 07938 07939 07940 07941 07942 07943 07944 07945 07946 07947 07948 07949 07950 07951 07952 07953 07954 07955 07956 07957 07958 07959 07960 07961 07962 07963 07964 07965 07966 07967 07968 07969 07970 07971 07972 07973 07974 07975 07976 07977 07978 07979 07980 07981 07982 07983 07984 07985 07986 07987 07988 07989 07990 07991 07992 07993 07994 07995 07996 07997 07998 07999 08000 08001 08002 08003 08004 08005 08006 08007 08008 08009 08010 08011 08012 08013 08014 08015 08016 08017 08018 08019 08020 08021 08022 08023 08024 08025 08026 08027 08028 08029 08030 08031 08032 08033 08034 08035 08036 08037 08038 08039 08040 08041 08042 08043 08044 08045 08046 08047 08048 08049 08050 08051 08052 08053 08054 08055 08056 08057 08058 08059 08060 08061 08062 08063 08064 08065 08066 08067 08068 08069 08070 08071 08072 08073 08074 08075 08076 08077 08078 08079 08080 08081 08082 08083 08084 08085 08086 08087 08088 08089 08090 08091 08092 08093 08094 08095 08096 08097 08098 08099 08100 08101 08102 08103 08104 08105 08106 08107 08108 08109 08110 08111 08112 08113 08114 08115 08116 08117 08118 08119 08120 08121 08122 08123 08124 08125 08126 08127 08128 08129 08130 08131 08132 08133 08134 08135 08136 08137 08138 08139 08140 08141 08142 08143 08144 08145 08146 08147 08148 08149 08150 08151 08152 08153 08154 08155 08156 08157 08158 08159 08160 08161 08162 08163 08164 08165 08166 08167 08168 08169 08170 08171 08172 08173 08174 08175 08176 08177 08178 08179 08180 08181 08182 08183 08184 08185 08186 08187 08188 08189 08190 08191 08192 08193 08194 08195 08196 08197 08198 08199 08200 08201 08202 08203 08204 08205 08206 08207 08208 08209 08210 08211 08212 08213 08214 08215 08216 08217 08218 08219 08220 08221 08222 08223 08224 08225 08226 08227 08228 08229 08230 08231 08232 08233 08234 08235 08236 08237 08238 08239 08240 08241 08242 08243 08244 08245 08246 08247 08248 08249 08250 08251 08252 08253 08254 08255 08256 08257 08258 08259 08260 08261 08262 08263 08264 08265 08266 08267 08268 08269 08270 08271 08272 08273 08274 08275 08276 08277 08278 08279 08280 08281 08282 08283 08284 08285 08286 08287 08288 08289 08290 08291 08292 08293 08294 08295 08296 08297 08298 08299 08300 08301 08302 08303 08304 08305 08306 08307 08308 08309 08310 08311 08312 08313 08314 08315 08316 08317 08318 08319 08320 08321 08322 08323 08324 08325 08326 08327 08328 08329 08330 08331 08332 08333 08334 08335 08336 08337 08338 08339 08340 08341 08342 08343 08344 08345 08346 08347 08348 08349 08350 08351 08352 08353 08354 08355 08356 08357 08358 08359 08360 08361 08362 08363 08364 08365 08366 08367 08368 08369 08370 08371 08372 08373 08374 08375 08376 08377 08378 08379 08380 08381 08382 08383 08384 08385 08386 08387 08388 08389 08390 08391 08392 08393 08394 08395 08396 08397 08398 08399 08400 08401 08402 08403 08404 08405 08406 08407 08408 08409 08410 08411 08412 08413 08414 08415 08416 08417 08418 08419 08420 08421 08422 08423 08424 08425 08426 08427 08428 08429 08430 08431 08432 08433 08434 08435 08436 08437 08438 08439 08440 08441 08442 08443 08444 08445 08446 08447 08448 08449 08450 08451 08452 08453 08454 08455 08456 08457 08458 08459 08460 08461 08462 08463 08464 08465 08466 08467 08468 08469 08470 08471 08472 08473 08474 08475 08476 08477 08478 08479 08480 08481 08482 08483 08484 08485 08486 08487 08488 08489 08490 08491 08492 08493 08494 08495 08496 08497 08498 08499 08500 08501 08502 08503 08504 08505 08506 08507 08508 08509 08510 08511 08512 08513 08514 08515 08516 08517 08518 08519 08520 08521 08522 08523 08524 08525 08526 08527 08528 08529 08530 08531 08532 08533 08534 08535 08536 08537 08538 08539 08540 08541 08542 08543 08544 08545 08546 08547 08548 08549 08550 08551 08552 08553 08554 08555 08556 08557 08558 08559 08560 08561 08562 08563 08564 08565 08566 08567 08568 08569 08570 08571 08572 08573 08574 08575 08576 08577 08578 08579 08580 08581 08582 08583 08584 08585 08586 08587 08588 08589 08590 08591 08592 08593 08594 08595 08596 08597 08598 08599 08600 08601 08602 08603 08604 08605 08606 08607 08608 08609 08610 08611 08612 08613 08614 08615 08616 08617 08618 08619 08620 08621 08622 08623 08624 08625 08626 08627 08628 08629 08630 08631 08632 08633 08634 08635 08636 08637 08638 08639 08640 08641 08642 08643 08644 08645 08646 08647 08648 08649 08650 08651 08652 08653 08654 08655 08656 08657 08658 08659 08660 08661 08662 08663 08664 08665 08666 08667 08668 08669 08670 08671 08672 08673 08674 08675 08676 08677 08678 08679 08680 08681 08682 08683 08684 08685 08686 08687 08688 08689 08690 08691 08692 08693 08694 08695 08696 08697 08698 08699 08700 08701 08702 08703 08704 08705 08706 08707 08708 08709 08710 08711 08712 08713 08714 08715 08716 08717 08718 08719 08720 08721 08722 08723 08724 08725 08726 08727 08728 08729 08730 08731 08732 08733 08734 08735 08736 08737 08738 08739 08740 08741 08742 08743 08744 08745 08746 08747 08748 08749 08750 08751 08752 08753 08754 08755 08756 08757 08758 08759 08760 08761 08762 08763 08764 08765 08766 08767 08768 08769 08770 08771 08772 08773 08774 08775 08776 08777 08778 08779 08780 08781 08782 08783 08784 08785 08786 08787 08788 08789 08790 08791 08792 08793 08794 08795 08796 08797 08798 08799 08800 08801 08802 08803 08804 08805 08806 08807 08808 08809 08810 08811 08812 08813 08814 08815 08816 08817 08818 08819 08820 08821 08822 08823 08824 08825 08826 08827 08828 08829 08830 08831 08832 08833 08834 08835 08836 08837 08838 08839 08840 08841 08842 08843 08844 08845 08846 08847 08848 08849 08850 08851 08852 08853 08854 08855 08856 08857 08858 08859 08860 08861 08862 08863 08864 08865 08866 08867 08868 08869 08870 08871 08872 08873 08874 08875 08876 08877 08878 08879 08880 08881 08882 08883 08884 08885 08886 08887 08888 08889 08890 08891 08892 08893 08894 08895 08896 08897 08898 08899 08900 08901 08902 08903 08904 08905 08906 08907 08908 08909 08910 08911 08912 08913 08914 08915 08916 08917 08918 08919 08920 08921 08922 08923 08924 08925 08926 08927 08928 08929 08930 08931 08932 08933 08934 08935 08936 08937 08938 08939 08940 08941 08942 08943 08944 08945 08946 08947 08948 08949 08950 08951 08952 08953 08954 08955 08956 08957 08958 08959 08960 08961 08962 08963 08964 08965 08966 08967 08968 08969 08970 08971 08972 08973 08974 08975 08976 08977 08978 08979 08980 08981 08982 08983 08984 08985 08986 08987 08988 08989 08990 08991 08992 08993 08994 08995 08996 08997 08998 08999 09000 09001 09002 09003 09004 09005 09006 09007 09008 09009 09010 09011 09012 09013 09014 09015 09016 09017 09018 09019 09020 09021 09022 09023 09024 09025 09026 09027 09028 09029 09030 09031 09032 09033 09034 09035 09036 09037 09038 09039 09040 09041 09042 09043 09044 09045 09046 09047 09048 09049 09050 09051 09052 09053 09054 09055 09056 09057 09058 09059 09060 09061 09062 09063 09064 09065 09066 09067 09068 09069 09070 09071 09072 09073 09074 09075 09076 09077 09078 09079 09080 09081 09082 09083 09084 09085 09086 09087 09088 09089 09090 09091 09092 09093 09094 09095 09096 09097 09098 09099 09100 09101 09102 09103 09104 09105 09106 09107 09108 09109 09110 09111 09112 09113 09114 09115 09116 09117 09118 09119 09120 09121 09122 09123 09124 09125 09126 09127 09128 09129 09130 09131 09132 09133 09134 09135 09136 09137 09138 09139 09140 09141 09142 09143 09144 09145 09146 09147 09148 09149 09150 09151 09152 09153 09154 09155 09156 09157 09158 09159 09160 09161 09162 09163 09164 09165 09166 09167 09168 09169 09170 09171 09172 09173 09174 09175 09176 09177 09178 09179 09180 09181 09182 09183 09184 09185 09186 09187 09188 09189 09190 09191 09192 09193 09194 09195 09196 09197 09198 09199 09200 09201 09202 09203 09204 09205 09206 09207 09208 09209 09210 09211 09212 09213 09214 09215 09216 09217 09218 09219 09220 09221 09222 09223 09224 09225 09226 09227 09228 09229 09230 09231 09232 09233 09234 09235 09236 09237 09238 09239 09240 09241 09242 09243 09244 09245 09246 09247 09248 09249 09250 09251 09252 09253 09254 09255 09256 09257 09258 09259 09260 09261 09262 09263 09264 09265 09266 09267 09268 09269 09270 09271 09272 09273 09274 09275 09276 09277 09278 09279 09280 09281 09282 09283 09284 09285 09286 09287 09288 09289 09290 09291 09292 09293 09294 09295 09296 09297 09298 09299 09300 09301 09302 09303 09304 09305 09306 09307 09308 09309 09310 09311 09312 09313 09314 09315 09316 09317 09318 09319 09320 09321 09322 09323 09324 09325 09326 09327 09328 09329 09330 09331 09332 09333 09334 09335 09336 09337 09338 09339 09340 09341 09342 09343 09344 09345 09346 09347 09348 09349 09350 09351 09352 09353 09354 09355 09356 09357 09358 09359 09360 09361 09362 09363 09364 09365 09366 09367 09368 09369 09370 09371 09372 09373 09374 09375 09376 09377 09378 09379 09380 09381 09382 09383 09384 09385 09386 09387 09388 09389 09390 09391 09392 09393 09394 09395 09396 09397 09398 09399 09400 09401 09402 09403 09404 09405 09406 09407 09408 09409 09410 09411 09412 09413 09414 09415 09416 09417 09418 09419 09420 09421 09422 09423 09424 09425 09426 09427 09428 09429 09430 09431 09432 09433 09434 09435 09436 09437 09438 09439 09440 09441 09442 09443 09444 09445 09446 09447 09448 09449 09450 09451 09452 09453 09454 09455 09456 09457 09458 09459 09460 09461 09462 09463 09464 09465 09466 09467 09468 09469 09470 09471 09472 09473 09474 09475 09476 09477 09478 09479 09480 09481 09482 09483 09484 09485 09486 09487 09488 09489 09490 09491 09492 09493 09494 09495 09496 09497 09498 09499 09500 09501 09502 09503 09504 09505 09506 09507 09508 09509 09510 09511 09512 09513 09514 09515 09516 09517 09518 09519 09520 09521 09522 09523 09524 09525 09526 09527 09528 09529 09530 09531 09532 09533 09534 09535 09536 09537 09538 09539 09540 09541 09542 09543 09544 09545 09546 09547 09548 09549 09550 09551 09552 09553 09554 09555 09556 09557 09558 09559 09560 09561 09562 09563 09564 09565 09566 09567 09568 09569 09570 09571 09572 09573 09574 09575 09576 09577 09578 09579 09580 09581 09582 09583 09584 09585 09586 09587 09588 09589 09590 09591 09592 09593 09594 09595 09596 09597 09598 09599 09600 09601 09602 09603 09604 09605 09606 09607 09608 09609 09610 09611 09612 09613 09614 09615 09616 09617 09618 09619 09620 09621 09622 09623 09624 09625 09626 09627 09628 09629 09630 09631 09632 09633 09634 09635 09636 09637 09638 09639 09640 09641 09642 09643 09644 09645 09646 09647 09648 09649 09650 09651 09652 09653 09654 09655 09656 09657 09658 09659 09660 09661 09662 09663 09664 09665 09666 09667 09668 09669 09670 09671 09672 09673 09674 09675 09676 09677 09678 09679 09680 09681 09682 09683 09684 09685 09686 09687 09688 09689 09690 09691 09692 09693 09694 09695 09696 09697 09698 09699 09700 09701 09702 09703 09704 09705 09706 09707 09708 09709 09710 09711 09712 09713 09714 09715 09716 09717 09718 09719 09720 09721 09722 09723 09724 09725 09726 09727 09728 09729 09730 09731 09732 09733 09734 09735 09736 09737 09738 09739 09740 09741 09742 09743 09744 09745 09746 09747 09748 09749 09750 09751 09752 09753 09754 09755 09756 09757 09758 09759 09760 09761 09762 09763 09764 09765 09766 09767 09768 09769 09770 09771 09772 09773 09774 09775 09776 09777 09778 09779 09780 09781 09782 09783 09784 09785 09786 09787 09788 09789 09790 09791 09792 09793 09794 09795 09796 09797 09798 09799 09800 09801 09802 09803 09804 09805 09806 09807 09808 09809 09810 09811 09812 09813 09814 09815 09816 09817 09818 09819 09820 09821 09822 09823 09824 09825 09826 09827 09828 09829 09830 09831 09832 09833 09834 09835 09836 09837 09838 09839 09840 09841 09842 09843 09844 09845 09846 09847 09848 09849 09850 09851 09852 09853 09854 09855 09856 09857 09858 09859 09860 09861 09862 09863 09864 09865 09866 09867 09868 09869 09870 09871 09872 09873 09874 09875 09876 09877 09878 09879 09880 09881 09882 09883 09884 09885 09886 09887 09888 09889 09890 09891 09892 09893 09894 09895 09896 09897 09898 09899 09900 09901 09902 09903 09904 09905 09906 09907 09908 09909 09910 09911 09912 09913 09914 09915 09916 09917 09918 09919 09920 09921 09922 09923 09924 09925 09926 09927 09928 09929 09930 09931 09932 09933 09934 09935 09936 09937 09938 09939 09940 09941 09942 09943 09944 09945 09946 09947 09948 09949 09950 09951 09952 09953 09954 09955 09956 09957 09958 09959 09960 09961 09962 09963 09964 09965 09966 09967 09968 09969 09970 09971 09972 09973 09974 09975 09976 09977 09978 09979 09980 09981 09982 09983 09984 09985 09986 09987 09988 09989 09990 09991 09992 09993 09994 09995 09996 09997 09998 09999 10000 10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016 10017 10018 10019 10020 10021 10022 10023 10024 10025 10026 10027 10028 10029 10030 10031 10032 10033 10034 10035 10036 10037 10038 10039 10040 10041 10042 10043 10044 10045 10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 10059 10060 10061 10062 10063 10064 10065 10066 10067 10068 10069 10070 10071 10072 10073 10074 10075 10076 10077 10078 10079 10080 10081 10082 10083 10084 10085 10086 10087 10088 10089 10090 10091 10092 10093 10094 10095 10096 10097 10098 10099 10100 10101 10102 10103 10104 10105 10106 10107 10108 10109 10110 10111 10112 10113 10114 10115 10116 10117 10118 10119 10120 10121 10122 10123 10124 10125 10126 10127 10128 10129 10130 10131 10132 10133 10134 10135 10136 10137 10138 10139 10140 10141 10142 10143 10144 10145 10146 10147 10148 10149 10150 10151 10152 10153 10154 10155 10156 10157 10158 10159 10160 10161 10162 10163 10164 10165 10166 10167 10168 10169 10170 10171 10172 10173 10174 10175 10176 10177 10178 10179 10180 10181 10182 10183 10184 10185 10186 10187 10188 10189 10190 10191 10192 10193 10194 10195 10196 10197 10198 10199 10200 10201 10202 10203 10204 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214 10215 10216 10217 10218 10219 10220 10221 10222 10223 10224 10225 10226 10227 10228 10229 10230 10231 10232 10233 10234 10235 10236 10237 10238 10239 10240 10241 10242 10243 10244 10245 10246 10247 10248 10249 10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260 10261 10262 10263 10264 10265 10266 10267 10268 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 10281 10282 10283 10284 10285 10286 10287 10288 10289 10290 10291 10292 10293 10294 10295 10296 10297 10298 10299 10300 10301 10302 10303 10304 10305 10306 10307 10308 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 10322 10323 10324 10325 10326 10327 10328 10329 10330 10331 10332 10333 10334 10335 10336 10337 10338 10339 10340 10341 10342 10343 10344 10345 10346 10347 10348 10349 10350 10351 10352 10353 10354 10355 10356 10357 10358 10359 10360 10361 10362 10363 10364 10365 10366 10367 10368 10369 10370 10371 10372 10373 10374 10375 10376 10377 10378 10379 10380 10381 10382 10383 10384 10385 10386 10387 10388 10389 10390 10391 10392 10393 10394 10395 10396 10397 10398 10399 10400 10401 10402 10403 10404 10405 10406 10407 10408 10409 10410 10411 10412 10413 10414 10415 10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 10429 10430 10431 10432 10433 10434 10435 10436 10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 10468 10469 10470 10471 10472 10473 10474 10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 10487 10488 10489 10490 10491 10492 10493 10494 10495 10496 10497 10498 10499 10500 10501 10502 10503 10504 10505 10506 10507 10508 10509 10510 10511 10512 10513 10514 10515 10516 10517 10518 10519 10520 10521 10522 10523 10524 10525 10526 10527 10528 10529 10530 10531 10532 10533 10534 10535 10536 10537 10538 10539 10540 10541 10542 10543 10544 10545 10546 10547 10548 10549 10550 10551 10552 10553 10554 10555 10556 10557 10558 10559 10560 10561 10562 10563 10564 10565 10566 10567 10568 10569 10570 10571 10572 10573 10574 10575 10576 10577 10578 10579 10580 10581 10582 10583 10584 10585 10586 10587 10588 10589 10590 10591 10592 10593 10594 10595 10596 10597 10598 10599 10600 10601 10602 10603 10604 10605 10606 10607 10608 10609 10610 10611 10612 10613 10614 10615 10616 10617 10618 10619 10620 10621 10622 10623 10624 10625 10626 10627 10628 10629 10630 10631 10632 10633 10634 10635 10636 10637 10638 10639 10640 10641 10642 10643 10644 10645 10646 10647 10648 10649 10650 10651 10652 10653 10654 10655 10656 10657 10658 10659 10660 10661 10662 10663 10664 10665 10666 10667 10668 10669 10670 10671 10672 10673 10674 10675 10676 10677 10678 10679 10680 10681 10682 10683 10684 10685 10686 10687 10688 10689 10690 10691 10692 10693 10694 10695 10696 10697 10698 10699 10700 10701 10702 10703 10704 10705 10706 10707 10708 10709 10710 10711 10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 10726 10727 10728 10729 10730 10731 10732 10733 10734 10735 10736 10737 10738 10739 10740 10741 10742 10743 10744 10745 10746 10747 10748 10749 10750 10751 10752 10753 10754 10755 10756 10757 10758 10759 10760 10761 10762 10763 10764 10765 10766 10767 10768 10769 10770 10771 10772 10773 10774 10775 10776 10777 10778 10779 10780 10781 10782 10783 10784 10785 10786 10787 10788 10789 10790 10791 10792 10793 10794 10795 10796 10797 10798 10799 10800 10801 10802 10803 10804 10805 10806 10807 10808 10809 10810 10811 10812 10813 10814 10815 10816 10817 10818 10819 10820 10821 10822 10823 10824 10825 10826 10827 10828 10829 10830 10831 10832 10833 10834 10835 10836 10837 10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848 10849 10850 10851 10852 10853 10854 10855 10856 10857 10858 10859 10860 10861 10862 10863 10864 10865 10866 10867 10868 10869 10870 10871 10872 10873 10874 10875 10876 10877 10878 10879 10880 10881 10882 10883 10884 10885 10886 10887 10888 10889 10890 10891 10892 10893 10894 10895 10896 10897 10898 10899 10900 10901 10902 10903 10904 10905 10906 10907 10908 10909 10910 10911 10912 10913 10914 10915 10916 10917 10918 10919 10920 10921 10922 10923 10924 10925 10926 10927 10928 10929 10930 10931 10932 10933 10934 10935 10936 10937 10938 10939 10940 10941 10942 10943 10944 10945 10946 10947 10948 10949 10950 10951 10952 10953 10954 10955 10956 10957 10958 10959 10960 10961 10962 10963 10964 10965 10966 10967 10968 10969 10970 10971 10972 10973 10974 10975 10976 10977 10978 10979 10980 10981 10982 10983 10984 10985 10986 10987 10988 10989 10990 10991 10992 10993 10994 10995 10996 10997 10998 10999 11000 11001 11002 11003 11004 11005 11006 11007 11008 11009 11010 11011 11012 11013 11014 11015 11016 11017 11018 11019 11020 11021 11022 11023 11024 11025 11026 11027 11028 11029 11030 11031 11032 11033 11034 11035 11036 11037 11038 11039 11040 11041 11042 11043 11044 11045 11046 11047 11048 11049 11050 11051 11052 11053 11054 11055 11056 11057 11058 11059 11060 11061 11062 11063 11064 11065 11066 11067 11068 11069 11070 11071 11072 11073 11074 11075 11076 11077 11078 11079 11080 11081 11082 11083 11084 11085 11086 11087 11088 11089 11090 11091 11092 11093 11094 11095 11096 11097 11098 11099 11100 11101 11102 11103 11104 11105 11106 11107 11108 11109 11110 11111 11112 11113 11114 11115 11116 11117 11118 11119 11120 11121 11122 11123 11124 11125 11126 11127 11128 11129 11130 11131 11132 11133 11134 11135 11136 11137 11138 11139 11140 11141 11142 11143 11144 11145 11146 11147 11148 11149 11150 11151 11152 11153 11154 11155 11156 11157 11158 11159 11160 11161 11162 11163 11164 11165 11166 11167 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 11183 11184 11185 11186 11187 11188 11189 11190 11191 11192 11193 11194 11195 11196 11197 11198 11199 11200 11201 11202 11203 11204 11205 11206 11207 11208 11209 11210 11211 11212 11213 11214 11215 11216 11217 11218 11219 11220 11221 11222 11223 11224 11225 11226 11227 11228 11229 11230 11231 11232 11233 11234 11235 11236 11237 11238 11239 11240 11241 11242 11243 11244 11245 11246 11247 11248 11249 11250 11251 11252 11253 11254 11255 11256 11257 11258 11259 11260 11261 11262 11263 11264 11265 11266 11267 11268 11269 11270 11271 11272 11273 11274 11275 11276 11277 11278 11279 11280 11281 11282 11283 11284 11285 11286 11287 11288 11289 11290 11291 11292 11293 11294 11295 11296 11297 11298 11299 11300 11301 11302 11303 11304 11305 11306 11307 11308 11309 11310 11311 11312 11313 11314 11315 11316 11317 11318 11319 11320 11321 11322 11323 11324 11325 11326 11327 11328 11329 11330 11331 11332 11333 11334 11335 11336 11337 11338 11339 11340 11341 11342 11343 11344 11345 11346 11347 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 11359 11360 11361 11362 11363 11364 11365 11366 11367 11368 11369 11370 11371 11372 11373 11374 11375 11376 11377 11378 11379 11380 11381 11382 11383 11384 11385 11386 11387 11388 11389 11390 11391 11392 11393 11394 11395 11396 11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 11408 11409 11410 11411 11412 11413 11414 11415 11416 11417 11418 11419 11420 11421 11422 11423 11424 11425 11426 11427 11428 11429 11430 11431 11432 11433 11434 11435 11436 11437 11438 11439 11440 11441 11442 11443 11444 11445 11446 11447 11448 11449 11450 11451 11452 11453 11454 11455 11456 11457 11458 11459 11460 11461 11462 11463 11464 11465 11466 11467 11468 11469 11470 11471 11472 11473 11474 11475 11476 11477 11478 11479 11480 11481 11482 11483 11484 11485 11486 11487 11488 11489 11490 11491 11492 11493 11494 11495 11496 11497 11498 11499 11500 11501 11502 11503 11504 11505 11506 11507 11508 11509 11510 11511 11512 11513 11514 11515 11516 11517 11518 11519 11520 11521 11522 11523 11524 11525 11526 11527 11528 11529 11530 11531 11532 11533 11534 11535 11536 11537 11538 11539 11540 11541 11542 11543 11544 11545 11546 11547 11548 11549 11550 11551 11552 11553 11554 11555 11556 11557 11558 11559 11560 11561 11562 11563 11564 11565 11566 11567 11568 11569 11570 11571 11572 11573 11574 11575 11576 11577 11578 11579 11580 11581 11582 11583 11584 11585 11586 11587 11588 11589 11590 11591 11592 11593 11594 11595 11596 11597 11598 11599 11600 11601 11602 11603 11604 11605 11606 11607 11608 11609 11610 11611 11612 11613 11614 11615 11616 11617 11618 11619 11620 11621 11622 11623 11624 11625 11626 11627 11628 11629 11630 11631 11632 11633 11634 11635 11636 11637 11638 11639 11640 11641 11642 11643 11644 11645 11646 11647 11648 11649 11650 11651 11652 11653 11654 11655 11656 11657 11658 11659 11660 11661 11662 11663 11664 11665 11666 11667 11668 11669 11670 11671 11672 11673 11674 11675 11676 11677 11678 11679 11680 11681 11682 11683 11684 11685 11686 11687 11688 11689 11690 11691 11692 11693 11694 11695 11696 11697 11698 11699 11700 11701 11702 11703 11704 11705 11706 11707 11708 11709 11710 11711 11712 11713 11714 11715 11716 11717 11718 11719 11720 11721 11722 11723 11724 11725 11726 11727 11728 11729 11730 11731 11732 11733 11734 11735 11736 11737 11738 11739 11740 11741 11742 11743 11744 11745 11746 11747 11748 11749 11750 11751 11752 11753 11754 11755 11756 11757 11758 11759 11760 11761 11762 11763 11764 11765 11766 11767 11768 11769 11770 11771 11772 11773 11774 11775 11776 11777 11778 11779 11780 11781 11782 11783 11784 11785 11786 11787 11788 11789 11790 11791 11792 11793 11794 11795 11796 11797 11798 11799 11800 11801 11802 11803 11804 11805 11806 11807 11808 11809 11810 11811 11812 11813 11814 11815 11816 11817 11818 11819 11820 11821 11822 11823 11824 11825 11826 11827 11828 11829 11830 11831 11832 11833 11834 11835 11836 11837 11838 11839 11840 11841 11842 11843 11844 11845 11846 11847 11848 11849 11850 11851 11852 11853 11854 11855 11856 11857 11858 11859 11860 11861 11862 11863 11864 11865 11866 11867 11868 11869 11870 11871 11872 11873 11874 11875 11876 11877 11878 11879 11880 11881 11882 11883 11884 11885 11886 11887 11888 11889 11890 11891 11892 11893 11894 11895 11896 11897 11898 11899 11900 11901 11902 11903 11904 11905 11906 11907 11908 11909 11910 11911 11912 11913 11914 11915 11916 11917 11918 11919 11920 11921 11922 11923 11924 11925 11926 11927 11928 11929 11930 11931 11932 11933 11934 11935 11936 11937 11938 11939 11940 11941 11942 11943 11944 11945 11946 11947 11948 11949 11950 11951 11952 11953 11954 11955 11956 11957 11958 11959 11960 11961 11962 11963 11964 11965 11966 11967 11968 11969 11970 11971 11972 11973 11974 11975 11976 11977 11978 11979 11980 11981 11982 11983 11984 11985 11986 11987 11988 11989 11990 11991 11992 11993 11994 11995 11996 11997 11998 11999 12000 12001 12002 12003 12004 12005 12006 12007 12008 12009 12010 12011 12012 12013 12014 12015 12016 12017 12018 12019 12020 12021 12022 12023 12024 12025 12026 12027 12028 12029 12030 12031 12032 12033 12034 12035 12036 12037 12038 12039 12040 12041 12042 12043 12044 12045 12046 12047 12048 12049 12050 12051 12052 12053 12054 12055 12056 12057 12058 12059 12060 12061 12062 12063 12064 12065 12066 12067 12068 12069 12070 12071 12072 12073 12074 12075 12076 12077 12078 12079 12080 12081 12082 12083 12084 12085 12086 12087 12088 12089 12090 12091 12092 12093 12094 12095 12096 12097 12098 12099 12100 12101 12102 12103 12104 12105 12106 12107 12108 12109 12110 12111 12112 12113 12114 12115 12116 12117 12118 12119 12120 12121 12122 12123 12124 12125 12126 12127 12128 12129 12130 12131 12132 12133 12134 12135 12136 12137 12138 12139 12140 12141 12142 12143 12144 12145 12146 12147 12148 12149 12150 12151 12152 12153 12154 12155 12156 12157 12158 12159 12160 12161 12162 12163 12164 12165 12166 12167 12168 12169 12170 12171 12172 12173 12174 12175 12176 12177 12178 12179 12180 12181 12182 12183 12184 12185 12186 12187 12188 12189 12190 12191 12192 12193 12194 12195 12196 12197 12198 12199 12200 12201 12202 12203 12204 12205 12206 12207 12208 12209 12210 12211 12212 12213 12214 12215 12216 12217 12218 12219 12220 12221 12222 12223 12224 12225 12226 12227 12228 12229 12230 12231 12232 12233 12234 12235 12236 12237 12238 12239 12240 12241 12242 12243 12244 12245 12246 12247 12248 12249 12250 12251 12252 12253 12254 12255 12256 12257 12258 12259 12260 12261 12262 12263 12264 12265 12266 12267 12268 12269 12270 12271 12272 12273 12274 12275 12276 12277 12278 12279 12280 12281 12282 12283 12284 12285 12286 12287 12288 12289 12290 12291 12292 12293 12294 12295 12296 12297 12298 12299 12300 12301 12302 12303 12304 12305 12306 12307 12308 12309 12310 12311 12312 12313 12314 12315 12316 12317 12318 12319 12320 12321 12322 12323 12324 12325 12326 12327 12328 12329 12330 12331 12332 12333 12334 12335 12336 12337 12338 12339 12340 12341 12342 12343 12344 12345 12346 12347 12348 12349 12350 12351 12352 12353 12354 12355 12356 12357 12358 12359 12360 12361 12362 12363 12364 12365 12366 12367 12368 12369 12370 12371 12372 12373 12374 12375 12376 12377 12378 12379 12380 12381 12382 12383 12384 12385 12386 12387 12388 12389 12390 12391 12392 12393 12394 12395 12396 12397 12398 12399 12400 12401 12402 12403 12404 12405 12406 12407 12408 12409 12410 12411 12412 12413 12414 12415 12416 12417 12418 12419 12420 12421 12422 12423 12424 12425 12426 12427 12428 12429 12430 12431 12432 12433 12434 12435 12436 12437 12438 12439 12440 12441 12442 12443 12444 12445 12446 12447 12448 12449 12450 12451 12452 12453 12454 12455 12456 12457 12458 12459 12460 12461 12462 12463 12464 12465 12466 12467 12468 12469 12470 12471 12472 12473 12474 12475 12476 12477 12478 12479 12480 12481 12482 12483 12484 12485 12486 12487 12488 12489 12490 12491 12492 12493 12494 12495 12496 12497 12498 12499 12500 12501 12502 12503 12504 12505 12506 12507 12508 12509 12510 12511 12512 12513 12514 12515 12516 12517 12518 12519 12520 12521 12522 12523 12524 12525 12526 12527 12528 12529 12530 12531 12532 12533 12534 12535 12536 12537 12538 12539 12540 12541 12542 12543 12544 12545 12546 12547 12548 12549 12550 12551 12552 12553 12554 12555 12556 12557 12558 12559 12560 12561 12562 12563 12564 12565 12566 12567 12568 12569 12570 12571 12572 12573 12574 12575 12576 12577 12578 12579 12580 12581 12582 12583 12584 12585 12586 12587 12588 12589 12590 12591 12592 12593 12594 12595 12596 12597 12598 12599 12600 12601 12602 12603 12604 12605 12606 12607 12608 12609 12610 12611 12612 12613 12614 12615 12616 12617 12618 12619 12620 12621 12622 12623 12624 12625 12626 12627 12628 12629 12630 12631 12632 12633 12634 12635 12636 12637 12638 12639 12640 12641 12642 12643 12644 12645 12646 12647 12648 12649 12650 12651 12652 12653 12654 12655 12656 12657 12658 12659 12660 12661 12662 12663 12664 12665 12666 12667 12668 12669 12670 12671 12672 12673 12674 12675 12676 12677 12678 12679 12680 12681 12682 12683 12684 12685 12686 12687 12688 12689 12690 12691 12692 12693 12694 12695 12696 12697 12698 12699 12700 12701 12702 12703 12704 12705 12706 12707 12708 12709 12710 12711 12712 12713 12714 12715 12716 12717 12718 12719 12720 12721 12722 12723 12724 12725 12726 12727 12728 12729 12730 12731 12732 12733 12734 12735 12736 12737 12738 12739 12740 12741 12742 12743 12744 12745 12746 12747 12748 12749 12750 12751 12752 12753 12754 12755 12756 12757 12758 12759 12760 12761 12762 12763 12764 12765 12766 12767 12768 12769 12770 12771 12772 12773 12774 12775 12776 12777 12778 12779 12780 12781 12782 12783 12784 12785 12786 12787 12788 12789 12790 12791 12792 12793 12794 12795 12796 12797 12798 12799 12800 12801 12802 12803 12804 12805 12806 12807 12808 12809 12810 12811 12812 12813 12814 12815 12816 12817 12818 12819 12820 12821 12822 12823 12824 12825 12826 12827 12828 12829 12830 12831 12832 12833 12834 12835 12836 12837 12838 12839 12840 12841 12842 12843 12844 12845 12846 12847 12848 12849 12850 12851 12852 12853 12854 12855 12856 12857 12858 12859 12860 12861 12862 12863 12864 12865 12866 12867 12868 12869 12870 12871 12872 12873 12874 12875 12876 12877 12878 12879 12880 12881 12882 12883 12884 12885 12886 12887 12888 12889 12890 12891 12892 12893 12894 12895 12896 12897 12898 12899 12900 12901 12902 12903 12904 12905 12906 12907 12908 12909 12910 12911 12912 12913 12914 12915 12916 12917 12918 12919 12920 12921 12922 12923 12924 12925 12926 12927 12928 12929 12930 12931 12932 12933 12934 12935 12936 12937 12938 12939 12940 12941 12942 12943 12944 12945 12946 12947 12948 12949 12950 12951 12952 12953 12954 12955 12956 12957 12958 12959 12960 12961 12962 12963 12964 12965 12966 12967 12968 12969 12970 12971 12972 12973 12974 12975 12976 12977 12978 12979 12980 12981 12982 12983 12984 12985 12986 12987 12988 12989 12990 12991 12992 12993 12994 12995 12996 12997 12998 12999 13000 13001 13002 13003 13004 13005 13006 13007 13008 13009 13010 13011 13012 13013 13014 13015 13016 13017 13018 13019 13020 13021 13022 13023 13024 13025 13026 13027 13028 13029 13030 13031 13032 13033 13034 13035 13036 13037 13038 13039 13040 13041 13042 13043 13044 13045 13046 13047 13048 13049 13050 13051 13052 13053 13054 13055 13056 13057 13058 13059 13060 13061 13062 13063 13064 13065 13066 13067 13068 13069 13070 13071 13072 13073 13074 13075 13076 13077 13078 13079 13080 13081 13082 13083 13084 13085 13086 13087 13088 13089 13090 13091 13092 13093 13094 13095 13096 13097 13098 13099 13100 13101 13102 13103 13104 13105 13106 13107 13108 13109 13110 13111 13112 13113 13114 13115 13116 13117 13118 13119 13120 13121 13122 13123 13124 13125 13126 13127 13128 13129 13130 13131 13132 13133 13134 13135 13136 13137 13138 13139 13140 13141 13142 13143 13144 13145 13146 13147 13148 13149 13150 13151 13152 13153 13154 13155 13156 13157 13158 13159 13160 13161 13162 13163 13164 13165 13166 13167 13168 13169 13170 13171 13172 13173 13174 13175 13176 13177 13178 13179 13180 13181 13182 13183 13184 13185 13186 13187 13188 13189 13190 13191 13192 13193 13194 13195 13196 13197 13198 13199 13200 13201 13202 13203 13204 13205 13206 13207 13208 13209 13210 13211 13212 13213 13214 13215 13216 13217 13218 13219 13220 13221 13222 13223 13224 13225 13226 13227 13228 13229 13230 13231 13232 13233 13234 13235 13236 13237 13238 13239 13240 13241 13242 13243 13244 13245 13246 13247 13248 13249 13250 13251 13252 13253 13254 13255 13256 13257 13258 13259 13260 13261 13262 13263 13264 13265 13266 13267 13268 13269 13270 13271 13272 13273 13274 13275 13276 13277 13278 13279 13280 13281 13282 13283 13284 13285 13286 13287 13288 13289 13290 13291 13292 13293 13294 13295 13296 13297 13298 13299 13300 13301 13302 13303 13304 13305 13306 13307 13308 13309 13310 13311 13312 13313 13314 13315 13316 13317 13318 13319 13320 13321 13322 13323 13324 13325 13326 13327 13328 13329 13330 13331 13332 13333 13334 13335 13336 13337 13338 13339 13340 13341 13342 13343 13344 13345 13346 13347 13348 13349 13350 13351 13352 13353 13354 13355 13356 13357 13358 13359 13360 13361 13362 13363 13364 13365 13366 13367 13368 13369 13370 13371 13372 13373 13374 13375 13376 13377 13378 13379 13380 13381 13382 13383 13384 13385 13386 13387 13388 13389 13390 13391 13392 13393 13394 13395 13396 13397 13398 13399 13400 13401 13402 13403 13404 13405 13406 13407 13408 13409 13410 13411 13412 13413 13414 13415 13416 13417 13418 13419 13420 13421 13422 13423 13424 13425 13426 13427 13428 13429 13430 13431 13432 13433 13434 13435 13436 13437 13438 13439 13440 13441 13442 13443 13444 13445 13446 13447 13448 13449 13450 13451 13452 13453 13454 13455 13456 13457 13458 13459 13460 13461 13462 13463 13464 13465 13466 13467 13468 13469 13470 13471 13472 13473 13474 13475 13476 13477 13478 13479 13480 13481 13482 13483 13484 13485 13486 13487 13488 13489 13490 13491 13492 13493 13494 13495 13496 13497 13498 13499 13500 13501 13502 13503 13504 13505 13506 13507 13508 13509 13510 13511 13512 13513 13514 13515 13516 13517 13518 13519 13520 13521 13522 13523 13524 13525 13526 13527 13528 13529 13530 13531 13532 13533 13534 13535 13536 13537 13538 13539 13540 13541 13542 13543 13544 13545 13546 13547 13548 13549 13550 13551 13552 13553 13554 13555 13556 13557 13558 13559 13560 13561 13562 13563 13564 13565 13566 13567 13568 13569 13570 13571 13572 13573 13574 13575 13576 13577 13578 13579 13580 13581 13582 13583 13584 13585 13586 13587 13588 13589 13590 13591 13592 13593 13594 13595 13596 13597 13598 13599 13600 13601 13602 13603 13604 13605 13606 13607 13608 13609 13610 13611 13612 13613 13614 13615 13616 13617 13618 13619 13620 13621 13622 13623 13624 13625 13626 13627 13628 13629 13630 13631 13632 13633 13634 13635 13636 13637 13638 13639 13640 13641 13642 13643 13644 13645 13646 13647 13648 13649 13650 13651 13652 13653 13654 13655 13656 13657 13658 13659 13660 13661 13662 13663 13664 13665 13666 13667 13668 13669 13670 13671 13672 13673 13674 13675 13676 13677 13678 13679 13680 13681 13682 13683 13684 13685 13686 13687 13688 13689 13690 13691 13692 13693 13694 13695 13696 13697 13698 13699 13700 13701 13702 13703 13704 13705 13706 13707 13708 13709 13710 13711 13712 13713 13714 13715 13716 13717 13718 13719 13720 13721 13722 13723 13724 13725 13726 13727 13728 13729 13730 13731 13732 13733 13734 13735 13736 13737 13738 13739 13740 13741 13742 13743 13744 13745 13746 13747 13748 13749 13750 13751 13752 13753 13754 13755 13756 13757 13758 13759 13760 13761 13762 13763 13764 13765 13766 13767 13768 13769 13770 13771 13772 13773 13774 13775 13776 13777 13778 13779 13780 13781 13782 13783 13784 13785 13786 13787 13788 13789 13790 13791 13792 13793 13794 13795 13796 13797 13798 13799 13800 13801 13802 13803 13804 13805 13806 13807 13808 13809 13810 13811 13812 13813 13814 13815 13816 13817 13818 13819 13820 13821 13822 13823 13824 13825 13826 13827 13828 13829 13830 13831 13832 13833 13834 13835 13836 13837 13838 13839 13840 13841 13842 13843 13844 13845 13846 13847 13848 13849 13850 13851 13852 13853 13854 13855 13856 13857 13858 13859 13860 13861 13862 13863 13864 13865 13866 13867 13868 13869 13870 13871 13872 13873 13874 13875 13876 13877 13878 13879 13880 13881 13882 13883 13884 13885 13886 13887 13888 13889 13890 13891 13892 13893 13894 13895 13896 13897 13898 13899 13900 13901 13902 13903 13904 13905 13906 13907 13908 13909 13910 13911 13912 13913 13914 13915 13916 13917 13918 13919 13920 13921 13922 13923 13924 13925 13926 13927 13928 13929 13930 13931 13932 13933 13934 13935 13936 13937 13938 13939 13940 13941 13942 13943 13944 13945 13946 13947 13948 13949 13950 13951 13952 13953 13954 13955 13956 13957 13958 13959 13960 13961 13962 13963 13964 13965 13966 13967 13968 13969 13970 13971 13972 13973 13974 13975 13976 13977 13978 13979 13980 13981 13982 13983 13984 13985 13986 13987 13988 13989 13990 13991 13992 13993 13994 13995 13996 13997 13998 13999 14000 14001 14002 14003 14004 14005 14006 14007 14008 14009 14010 14011 14012 14013 14014 14015 14016 14017 14018 14019 14020 14021 14022 14023 14024 14025 14026 14027 14028 14029 14030 14031 14032 14033 14034 14035 14036 14037 14038 14039 14040 14041 14042 14043 14044 14045 14046 14047 14048 14049 14050 14051 14052 14053 14054 14055 14056 14057 14058 14059 14060 14061 14062 14063 14064 14065 14066 14067 14068 14069 14070 14071 14072 14073 14074 14075 14076 14077 14078 14079 14080 14081 14082 14083 14084 14085 14086 14087 14088 14089 14090 14091 14092 14093 14094 14095 14096 14097 14098 14099 14100 14101 14102 14103 14104 14105 14106 14107 14108 14109 14110 14111 14112 14113 14114 14115 14116 14117 14118 14119 14120 14121 14122 14123 14124 14125 14126 14127 14128 14129 14130 14131 14132 14133 14134 14135 14136 14137 14138 14139 14140 14141 14142 14143 14144 14145 14146 14147 14148 14149 14150 14151 14152 14153 14154 14155 14156 14157 14158 14159 14160 14161 14162 14163 14164 14165 14166 14167 14168 14169 14170 14171 14172 14173 14174 14175 14176 14177 14178 14179 14180 14181 14182 14183 14184 14185 14186 14187 14188 14189 14190 14191 14192 14193 14194 14195 14196 14197 14198 14199 14200 14201 14202 14203 14204 14205 14206 14207 14208 14209 14210 14211 14212 14213 14214 14215 14216 14217 14218 14219 14220 14221 14222 14223 |
//============================================================================= // ScriptedPawn. //============================================================================= class ScriptedPawn expands Pawn abstract native; // ---------------------------------------------------------------------- // Enumerations enum EDestinationType { DEST_Failure, DEST_NewLocation, DEST_SameLocation }; enum EAllianceType { ALLIANCE_Friendly, ALLIANCE_Neutral, ALLIANCE_Hostile }; enum ERaiseAlarmType { RAISEALARM_BeforeAttacking, RAISEALARM_BeforeFleeing, RAISEALARM_Never }; enum ESeekType { SEEKTYPE_None, SEEKTYPE_Sound, SEEKTYPE_Sight, SEEKTYPE_Guess, SEEKTYPE_Carcass }; enum EHitLocation { HITLOC_None, HITLOC_HeadFront, HITLOC_HeadBack, HITLOC_TorsoFront, HITLOC_TorsoBack, HITLOC_LeftLegFront, HITLOC_LeftLegBack, HITLOC_RightLegFront, HITLOC_RightLegBack, HITLOC_LeftArmFront, HITLOC_LeftArmBack, HITLOC_RightArmFront, HITLOC_RightArmBack }; enum ETurning { TURNING_None, TURNING_Left, TURNING_Right }; // ---------------------------------------------------------------------- // Structures struct WanderCandidates { var WanderPoint point; var Actor waypoint; var float dist; }; struct FleeCandidates { var HidePoint point; var Actor waypoint; var Vector location; var float score; var float dist; }; struct NearbyProjectile { var DeusExProjectile projectile; var vector location; var float dist; var float range; }; struct NearbyProjectileList { var NearbyProjectile list[8]; var vector center; }; struct InitialAllianceInfo { var() Name AllianceName; var() float AllianceLevel; var() bool bPermanent; }; struct AllianceInfoEx { var Name AllianceName; var float AllianceLevel; var float AgitationLevel; var bool bPermanent; }; struct InventoryItem { var() class<Inventory> Inventory; var() int Count; }; // ---------------------------------------------------------------------- // Variables var WanderPoint lastPoints[2]; var float Restlessness; // 0-1 var float Wanderlust; // 0-1 var float Cowardice; // 0-1 var(Combat) float BaseAccuracy; // 0-1 or thereabouts var(Combat) float MaxRange; var(Combat) float MinRange; var(Combat) float MinHealth; var(AI) float RandomWandering; // 0-1 var float sleepTime; var Actor destPoint; var Vector destLoc; var Vector useLoc; var Rotator useRot; var float seekDistance; // OBSOLETE var int SeekLevel; var ESeekType SeekType; var Pawn SeekPawn; var float CarcassTimer; var float CarcassHateTimer; // OBSOLETE var float CarcassCheckTimer; var name PotentialEnemyAlliance; var float PotentialEnemyTimer; var float BeamCheckTimer; var bool bSeekPostCombat; var bool bSeekLocation; var bool bInterruptSeek; var bool bAlliancesChanged; // set to True whenever someone changes AlliancesEx[i].AllianceLevel to indicate we must do alliance updating var bool bNoNegativeAlliances; // True means we know all alliances are currently +, allows us to skip CheckEnemyPresence's slow part var bool bSitAnywhere; var bool bSitInterpolation; var bool bStandInterpolation; var float remainingSitTime; var float remainingStandTime; var vector StandRate; var float ReloadTimer; var bool bReadyToReload; var(Pawn) class<carcass> CarcassType; // mesh to use when killed from the front // Advanced AI attributes. var(Orders) name Orders; // orders a creature is carrying out // will be initial state, plus creature will attempt // to return to this state var(Orders) name OrderTag; // tag of object referred to by orders var(Orders) name HomeTag; // tag of object to use as home base var(Orders) float HomeExtent; // extent of home base var actor OrderActor; // object referred to by orders (if applicable) var name NextAnim; // used in states with multiple, sequenced animations var float WalkingSpeed; // 0-1 var(Combat) float ProjectileSpeed; var name LastPainAnim; var float LastPainTime; var vector DesiredPrePivot; var float PrePivotTime; var vector PrePivotOffset; var bool bCanBleed; // true if an NPC can bleed var float BleedRate; // how profusely the NPC is bleeding; 0-1 var float DropCounter; // internal; used in tick() var() float ClotPeriod; // seconds it takes bleedRate to go from 1 to 0 var bool bAcceptBump; // ugly hack var bool bCanFire; // true if pawn is capable of shooting asynchronously var(AI) bool bKeepWeaponDrawn; // true if pawn should always keep weapon drawn var(AI) bool bShowPain; // true if pawn should play pain animations var(AI) bool bCanSit; // true if pawn can sit var(AI) bool bAlwaysPatrol; // true if stasis should be disabled during patrols var(AI) bool bPlayIdle; // true if pawn should fidget while he's standing var(AI) bool bLeaveAfterFleeing; // true if pawn should disappear after fleeing var(AI) bool bLikesNeutral; // true if pawn should treat neutrals as friendlies var(AI) bool bUseFirstSeatOnly; // true if only the nearest chair should be used for var(AI) bool bCower; // true if fearful pawns should cower instead of fleeing var HomeBase HomeActor; // home base var Vector HomeLoc; // location of home base var Vector HomeRot; // rotation of home base var bool bUseHome; // true if home base should be used var bool bInterruptState; // true if the state can be interrupted var bool bCanConverse; // true if the pawn can converse var() bool bImportant; // true if this pawn is game-critical var() bool bInvincible; // true if this pawn cannot be killed var bool bInitialized; // true if this pawn has been initialized var(Combat) bool bAvoidAim; // avoid enemy's line of fire var(Combat) bool bAimForHead; // aim for the enemy's head var(Combat) bool bDefendHome; // defend the home base var bool bCanCrouch; // whether we should crouch when firing var bool bSeekCover; // seek cover var bool bSprint; // sprint in random directions var(Combat) bool bUseFallbackWeapons; // use fallback weapons even when others are available var float AvoidAccuracy; // how well we avoid enemy's line of fire; 0-1 var bool bAvoidHarm; // avoid painful projectiles, gas clouds, etc. var float HarmAccuracy; // how well we avoid harm; 0-1 var float CrouchRate; // how often the NPC crouches, if bCrouch enabled; 0-1 var float SprintRate; // how often the NPC randomly sprints if bSprint enabled; 0-1 var float CloseCombatMult; // multiplier for how often the NPC sprints in close combat; 0-1 // If a stimulation is enabled, it causes an NPC to hate the stimulator //var(Stimuli) bool bHateFutz; var(Stimuli) bool bHateHacking; // new var(Stimuli) bool bHateWeapon; var(Stimuli) bool bHateShot; var(Stimuli) bool bHateInjury; var(Stimuli) bool bHateIndirectInjury; // new //var(Stimuli) bool bHateGore; var(Stimuli) bool bHateCarcass; // new var(Stimuli) bool bHateDistress; //var(Stimuli) bool bHateProjectiles; // If a reaction is enabled, the NPC will react appropriately to a stimulation var(Reactions) bool bReactFutz; // new var(Reactions) bool bReactPresence; // React to the presence of an enemy (attacking) var(Reactions) bool bReactLoudNoise; // Seek the source of a loud noise (seeking) var(Reactions) bool bReactAlarm; // Seek the source of an alarm (seeking) var(Reactions) bool bReactShot; // React to a gunshot fired by an enemy (attacking) //var(Reactions) bool bReactGore; // React to gore appropriately (seeking) var(Reactions) bool bReactCarcass; // React to gore appropriately (seeking) var(Reactions) bool bReactDistress; // React to distress appropriately (attacking) var(Reactions) bool bReactProjectiles; // React to harmful projectiles appropriately // If a fear is enabled, the NPC will run away from the stimulator var(Fears) bool bFearHacking; // Run away from a hacker var(Fears) bool bFearWeapon; // Run away from a person holding a weapon var(Fears) bool bFearShot; // Run away from a person who fires a shot var(Fears) bool bFearInjury; // Run away from a person who causes injury var(Fears) bool bFearIndirectInjury; // Run away from a person who causes indirect injury var(Fears) bool bFearCarcass; // Run away from a carcass var(Fears) bool bFearDistress; // Run away from a person causing distress var(Fears) bool bFearAlarm; // Run away from the source of an alarm var(Fears) bool bFearProjectiles; // Run away from a projectile var(AI) bool bEmitDistress; // TRUE if NPC should emit distress var(AI) ERaiseAlarmType RaiseAlarm; // When to raise an alarm var bool bLookingForEnemy; // TRUE if we're actually looking for enemies var bool bLookingForLoudNoise; // TRUE if we're listening for loud noises var bool bLookingForAlarm; // TRUE if we're listening for alarms var bool bLookingForDistress; // TRUE if we're looking for signs of distress var bool bLookingForProjectiles; // TRUE if we're looking for projectiles that can harm us var bool bLookingForFutz; // TRUE if we're looking for people futzing with stuff var bool bLookingForHacking; // TRUE if we're looking for people hacking stuff var bool bLookingForShot; // TRUE if we're listening for gunshots var bool bLookingForWeapon; // TRUE if we're looking for drawn weapons var bool bLookingForCarcass; // TRUE if we're looking for carcass events var bool bLookingForInjury; // TRUE if we're looking for injury events var bool bLookingForIndirectInjury; // TRUE if we're looking for secondary injury events var bool bFacingTarget; // True if pawn is facing its target var(Combat) bool bMustFaceTarget; // True if an NPC must face his target to fire var(Combat) float FireAngle; // TOTAL angle (in degrees) in which a pawn may fire if bMustFaceTarget is false var(Combat) float FireElevation; // Max elevation distance required to attack (0=elevation doesn't matter) var(AI) int MaxProvocations; var float AgitationSustainTime; var float AgitationDecayRate; var float AgitationTimer; var float AgitationCheckTimer; var float PlayerAgitationTimer; // hack var float FearSustainTime; var float FearDecayRate; var float FearTimer; var float FearLevel; var float EnemyReadiness; var float ReactionLevel; var float SurprisePeriod; var float SightPercentage; var float CycleTimer; var float CyclePeriod; var float CycleCumulative; var Pawn CycleCandidate; var float CycleDistance; var AlarmUnit AlarmActor; var float AlarmTimer; var float WeaponTimer; var float FireTimer; var float SpecialTimer; var float CrouchTimer; var float BackpedalTimer; var bool bHasShadow; var float ShadowScale; var bool bDisappear; var bool bInTransientState; // true if the NPC is in a 3rd-tier (transient) state, like TakeHit var(Alliances) InitialAllianceInfo InitialAlliances[8]; var AllianceInfoEx AlliancesEx[16]; var bool bReverseAlliances; var(Pawn) float BaseAssHeight; var(AI) float EnemyTimeout; var float CheckPeriod; var float EnemyLastSeen; var int SeatSlot; var Seat SeatActor; var int CycleIndex; var int BodyIndex; var bool bRunningStealthy; var bool bPausing; var bool bStaring; var bool bAttacking; var bool bDistressed; var bool bStunned; var bool bSitting; var bool bDancing; var bool bCrouching; var bool bCanTurnHead; var(AI) bool bTickVisibleOnly; // Temporary? var() bool bInWorld; var vector WorldPosition; var bool bWorldCollideActors; var bool bWorldBlockActors; var bool bWorldBlockPlayers; var() bool bHighlight; // should this object not highlight when focused? var(AI) bool bHokeyPokey; var bool bConvEndState; var(Inventory) InventoryItem InitialInventory[8]; // Initial inventory items carried by the pawn var Bool bConversationEndedNormally; var Bool bInConversation; var Actor ConversationActor; // Actor currently speaking to or speaking to us var() sound WalkSound; var float swimBubbleTimer; var bool bSpawnBubbles; var bool bUseSecondaryAttack; var bool bWalkAround; var bool bClearedObstacle; var bool bEnableCheckDest; var ETurning TurnDirection; var ETurning NextDirection; var Actor ActorAvoiding; var float AvoidWallTimer; var float AvoidBumpTimer; var float ObstacleTimer; var vector LastDestLoc; var vector LastDestPoint; var int DestAttempts; var float DeathTimer; var float EnemyTimer; var float TakeHitTimer; var name ConvOrders; var name ConvOrderTag; var float BurnPeriod; var float FutzTimer; var float DistressTimer; var vector SeatLocation; var Seat SeatHack; var bool bSeatLocationValid; var bool bSeatHackUsed; var bool bBurnedToDeath; var bool bHasCloak; var bool bCloakOn; var int CloakThreshold; var float CloakEMPTimer; var float poisonTimer; // time remaining before next poison TakeDamage var int poisonCounter; // number of poison TakeDamages remaining var int poisonDamage; // damage taken from poison effect var Pawn Poisoner; // person who initiated PoisonEffect damage var Name Carcasses[4]; // list of carcasses seen var int NumCarcasses; // number of carcasses seen var float walkAnimMult; var float runAnimMult; native(2102) final function ConBindEvents(); native(2105) final function bool IsValidEnemy(Pawn TestEnemy, optional bool bCheckAlliance); native(2106) final function EAllianceType GetAllianceType(Name AllianceName); native(2107) final function EAllianceType GetPawnAllianceType(Pawn QueryPawn); native(2108) final function bool HaveSeenCarcass(Name CarcassName); native(2109) final function AddCarcass(Name CarcassName); // ---------------------------------------------------------------------- // PreBeginPlay() // ---------------------------------------------------------------------- function PreBeginPlay() { local float saveBaseEyeHeight; // TODO: // // Okay, we need to save the base eye height right now becase it's // obliterated in Pawn.uc with the following: // // EyeHeight = 0.8 * CollisionHeight; //FIXME - if all baseeyeheights set right, use them // BaseEyeHeight = EyeHeight; // // This must be fixed after ECTS. saveBaseEyeHeight = BaseEyeHeight; Super.PreBeginPlay(); BaseEyeHeight = saveBaseEyeHeight; // create our shadow CreateShadow(); // Set our alliance SetAlliance(Alliance); // Set up callbacks UpdateReactionCallbacks(); } // ---------------------------------------------------------------------- // PostBeginPlay() // ---------------------------------------------------------------------- function PostBeginPlay() { Super.PostBeginPlay(); // Set up pain timer if (Region.Zone.bPainZone || HeadRegion.Zone.bPainZone || FootRegion.Zone.bPainZone) PainTime = 5.0; else if (HeadRegion.Zone.bWaterZone) PainTime = UnderWaterTime; // Handle holograms if ((Style != STY_Masked) && (Style != STY_Normal)) { SetSkinStyle(Style, None); SetCollision(false, false, false); KillShadow(); bHasShadow = False; } } // ---------------------------------------------------------------------- // PostPostBeginPlay() // ---------------------------------------------------------------------- function PostPostBeginPlay() { Super.PostPostBeginPlay(); // Bind any conversation events to this ScriptedPawn ConBindEvents(); } // ---------------------------------------------------------------------- // Destroyed() // ---------------------------------------------------------------------- simulated function Destroyed() { local DeusExPlayer player; // Pass a message to conPlay, if it exists in the player, that // this pawn has been destroyed. This is used to prevent // bad things from happening in converseations. player = DeusExPlayer(GetPlayerPawn()); if ((player != None) && (player.conPlay != None)) player.conPlay.ActorDestroyed(Self); Super.Destroyed(); } // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // GENERAL UTILITIES // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // InitializePawn() // ---------------------------------------------------------------------- function InitializePawn() { if (!bInitialized) { InitializeInventory(); InitializeAlliances(); InitializeHomeBase(); BlockReactions(); if (Alliance != '') ChangeAlly(Alliance, 1.0, true); if (!bInWorld) { // tricky bInWorld = true; LeaveWorld(); } // hack! animTimer[1] = 20.0; PlayTurnHead(LOOK_Forward, 1.0, 0.0001); bInitialized = true; } } // ---------------------------------------------------------------------- // InitializeInventory() // ---------------------------------------------------------------------- function InitializeInventory() { local int i, j; local Inventory inv; local Weapon weapons[8]; local int weaponCount; local Weapon firstWeapon; // Add initial inventory items weaponCount = 0; for (i=0; i<8; i++) { if ((InitialInventory[i].Inventory != None) && (InitialInventory[i].Count > 0)) { firstWeapon = None; for (j=0; j<InitialInventory[i].Count; j++) { inv = None; if (Class<Ammo>(InitialInventory[i].Inventory) != None) { inv = FindInventoryType(InitialInventory[i].Inventory); if (inv != None) Ammo(inv).AmmoAmount += Class<Ammo>(InitialInventory[i].Inventory).default.AmmoAmount; } if (inv == None) { inv = spawn(InitialInventory[i].Inventory, self); if (inv != None) { inv.InitialState='Idle2'; inv.GiveTo(Self); inv.SetBase(Self); if ((firstWeapon == None) && (Weapon(inv) != None)) firstWeapon = Weapon(inv); } } } if (firstWeapon != None) weapons[WeaponCount++] = firstWeapon; } } for (i=0; i<weaponCount; i++) { if ((weapons[i].AmmoType == None) && (weapons[i].AmmoName != None) && (weapons[i].AmmoName != Class'AmmoNone')) { weapons[i].AmmoType = Ammo(FindInventoryType(weapons[i].AmmoName)); if (weapons[i].AmmoType == None) { weapons[i].AmmoType = spawn(weapons[i].AmmoName); weapons[i].AmmoType.InitialState='Idle2'; weapons[i].AmmoType.GiveTo(Self); weapons[i].AmmoType.SetBase(Self); } } } SetupWeapon(false); } // ---------------------------------------------------------------------- // InitializeAlliances() // ---------------------------------------------------------------------- function InitializeAlliances() { local int i; for (i=0; i<8; i++) if (InitialAlliances[i].AllianceName != '') ChangeAlly(InitialAlliances[i].AllianceName, InitialAlliances[i].AllianceLevel, InitialAlliances[i].bPermanent); } // ---------------------------------------------------------------------- // InitializeHomeBase() // ---------------------------------------------------------------------- function InitializeHomeBase() { if (!bUseHome) { HomeActor = None; HomeLoc = Location; HomeRot = vector(Rotation); if (HomeTag == 'Start') bUseHome = true; else { HomeActor = HomeBase(FindTaggedActor(HomeTag, , Class'HomeBase')); if (HomeActor != None) { HomeLoc = HomeActor.Location; HomeRot = vector(HomeActor.Rotation); HomeExtent = HomeActor.Extent; bUseHome = true; } } HomeRot *= 100; } } // ---------------------------------------------------------------------- // AddInitialInventory() // ---------------------------------------------------------------------- function bool AddInitialInventory(class<Inventory> newInventory, optional int newCount) { local int i; if (newCount == 0) newCount = 1; for (i=0; i<8; i++) if ((InitialInventory[i].Inventory == None) && (InitialInventory[i].Count <= 0)) break; if (i < 8) { InitialInventory[i].Inventory = newInventory; InitialInventory[i].Count = newCount; return true; } else return false; } // ---------------------------------------------------------------------- // SetEnemy() // ---------------------------------------------------------------------- function bool SetEnemy(Pawn newEnemy, optional float newSeenTime, optional bool bForce) { if (bForce || IsValidEnemy(newEnemy)) { if (newEnemy != Enemy) EnemyTimer = 0; Enemy = newEnemy; EnemyLastSeen = newSeenTime; return True; } else return False; } // ---------------------------------------------------------------------- // SetState() // ---------------------------------------------------------------------- function SetState(Name stateName, optional Name labelName) { if (bInterruptState) GotoState(stateName, labelName); else SetNextState(stateName, labelName); } // ---------------------------------------------------------------------- // SetNextState() // ---------------------------------------------------------------------- function SetNextState(name newState, optional name newLabel) { if (!bInTransientState || !HasNextState()) { if ((newState != 'Conversation') && (newState != 'FirstPersonConversation')) { NextState = newState; NextLabel = newLabel; } } } // ---------------------------------------------------------------------- // ClearNextState() // ---------------------------------------------------------------------- function ClearNextState() { NextState = ''; NextLabel = ''; } // ---------------------------------------------------------------------- // HasNextState() // ---------------------------------------------------------------------- function bool HasNextState() { if ((NextState == '') || (NextState == GetStateName())) return false; else return true; } // ---------------------------------------------------------------------- // GotoNextState() // ---------------------------------------------------------------------- function GotoNextState() { local bool bSuccess; local name oldState, oldLabel; if (HasNextState()) { oldState = NextState; oldLabel = NextLabel; if (oldLabel == '') oldLabel = 'Begin'; ClearNextState(); GotoState(oldState, oldLabel); } else ClearNextState(); } // ---------------------------------------------------------------------- // SetOrders() // ---------------------------------------------------------------------- function SetOrders(Name orderName, optional Name newOrderTag, optional bool bImmediate) { local bool bHostile; local Pawn orderEnemy; switch (orderName) { case 'Attacking': case 'Fleeing': case 'Alerting': case 'Seeking': bHostile = true; break; default: bHostile = false; break; } if (!bHostile) { bSeatHackUsed = false; // hack! Orders = orderName; OrderTag = newOrderTag; if (bImmediate) FollowOrders(true); } else { ReactionLevel = 1.0; orderEnemy = Pawn(FindTaggedActor(newOrderTag, false, Class'Pawn')); if (orderEnemy != None) { ChangeAlly(orderEnemy.Alliance, -1, true); if (SetEnemy(orderEnemy)) SetState(orderName); } } } // ---------------------------------------------------------------------- // SetHomeBase() // ---------------------------------------------------------------------- function SetHomeBase(vector baseLocation, optional rotator baseRotator, optional float baseExtent) { local vector vectRot; if (baseExtent == 0) baseExtent = 800; HomeTag = ''; HomeActor = None; HomeLoc = baseLocation; HomeRot = vector(baseRotator)*100; HomeExtent = baseExtent; bUseHome = true; } // ---------------------------------------------------------------------- // ClearHomeBase() // ---------------------------------------------------------------------- function ClearHomeBase() { HomeTag = ''; bUseHome = false; } // ---------------------------------------------------------------------- // IsSeatValid() // ---------------------------------------------------------------------- function bool IsSeatValid(Actor checkActor) { local PlayerPawn player; local Seat checkSeat; checkSeat = Seat(checkActor); if (checkSeat == None) return false; else if (checkSeat.bDeleteMe) return false; else if (!bSitAnywhere && (VSize(checkSeat.Location-checkSeat.InitialPosition) > 70)) return false; else { player = GetPlayerPawn(); if (player != None) { if (player.CarriedDecoration == checkSeat) return false; } return true; } } // ---------------------------------------------------------------------- // SetDistress() // ---------------------------------------------------------------------- function SetDistress(bool bDistress) { bDistressed = bDistress; if (bDistress && bEmitDistress) AIStartEvent('Distress', EAITYPE_Visual); else AIEndEvent('Distress', EAITYPE_Visual); } // ---------------------------------------------------------------------- // SetDistressTimer() // ---------------------------------------------------------------------- function SetDistressTimer() { DistressTimer = 0; } // ---------------------------------------------------------------------- // SetSeekLocation() // ---------------------------------------------------------------------- function SetSeekLocation(Pawn seekCandidate, vector newLocation, ESeekType newSeekType, optional bool bNewPostCombat) { SetEnemy(None, 0, true); SeekPawn = seekCandidate; LastSeenPos = newLocation; bSeekLocation = True; SeekType = newSeekType; if (newSeekType == SEEKTYPE_Carcass) CarcassTimer = 120.0; if (newSeekType == SEEKTYPE_Sight) SeekLevel = Max(SeekLevel, 1); else SeekLevel = Max(SeekLevel, 3); if (bNewPostCombat) bSeekPostCombat = true; } // ---------------------------------------------------------------------- // GetCarcassData() // ---------------------------------------------------------------------- function bool GetCarcassData(actor sender, out Name killer, out Name alliance, out Name CarcassName, optional bool bCheckName) { local DeusExPlayer dxPlayer; local DeusExCarcass carcass; local POVCorpse corpseItem; local bool bCares; local bool bValid; alliance = ''; killer = ''; bValid = false; dxPlayer = DeusExPlayer(sender); carcass = DeusExCarcass(sender); if (dxPlayer != None) { corpseItem = POVCorpse(dxPlayer.inHand); if (corpseItem != None) { if (corpseItem.bEmitCarcass) { alliance = corpseItem.Alliance; killer = corpseItem.KillerAlliance; CarcassName = corpseItem.CarcassName; bValid = true; } } } else if (carcass != None) { if (carcass.bEmitCarcass) { alliance = carcass.Alliance; killer = carcass.KillerAlliance; CarcassName = carcass.CarcassName; bValid = true; } } bCares = false; if (bValid && (!bCheckName || !HaveSeenCarcass(CarcassName))) { if (bFearCarcass) bCares = true; else { if (GetAllianceType(alliance) == ALLIANCE_Friendly) { if (bHateCarcass) bCares = true; else if (bReactCarcass) { if (GetAllianceType(killer) == ALLIANCE_Hostile) bCares = true; } } } } return bCares; } // ---------------------------------------------------------------------- // ReactToFutz() // ---------------------------------------------------------------------- function ReactToFutz() { if (bLookingForFutz && bReactFutz && (FutzTimer <= 0) && !bDistressed) { FutzTimer = 2.0; PlayFutzSound(); } } // ---------------------------------------------------------------------- // ReactToProjectiles() // ---------------------------------------------------------------------- function ReactToProjectiles(Actor projectileActor) { local DeusExProjectile dxProjectile; local Pawn instigator; if ((bFearProjectiles || bReactProjectiles) && bLookingForProjectiles) { dxProjectile = DeusExProjectile(projectileActor); if ((dxProjectile == None) || IsProjectileDangerous(dxProjectile)) { instigator = Pawn(projectileActor); if (instigator == None) instigator = projectileActor.Instigator; if (instigator != None) { if (bFearProjectiles) IncreaseFear(instigator, 2.0); if (SetEnemy(instigator)) { SetDistressTimer(); HandleEnemy(); } else if (bFearProjectiles && IsFearful()) { SetDistressTimer(); SetEnemy(instigator, , true); GotoState('Fleeing'); } else if (bAvoidHarm) SetState('AvoidingProjectiles'); } } } } // ---------------------------------------------------------------------- // InstigatorToPawn() // ---------------------------------------------------------------------- function Pawn InstigatorToPawn(Actor eventActor) { local Pawn pawnActor; if (Inventory(eventActor) != None) { if (Inventory(eventActor).Owner != None) eventActor = Inventory(eventActor).Owner; } else if (DeusExDecoration(eventActor) != None) eventActor = GetPlayerPawn(); else if (DeusExProjectile(eventActor) != None) eventActor = eventActor.Instigator; pawnActor = Pawn(eventActor); if (pawnActor == self) pawnActor = None; return pawnActor; } // ---------------------------------------------------------------------- // EnableShadow() // ---------------------------------------------------------------------- function EnableShadow(bool bEnable) { if (Shadow != None) { if (bEnable) Shadow.AttachDecal(32,vect(0.1,0.1,0)); else Shadow.DetachDecal(); } } // ---------------------------------------------------------------------- // CreateShadow() // ---------------------------------------------------------------------- function CreateShadow() { if (bHasShadow && bInWorld) if (Shadow == None) Shadow = Spawn(class'Shadow', Self,, Location-vect(0,0,1)*CollisionHeight, rot(16384,0,0)); } // ---------------------------------------------------------------------- // KillShadow() // ---------------------------------------------------------------------- function KillShadow() { if (Shadow != None) { Shadow.Destroy(); Shadow = None; } } // ---------------------------------------------------------------------- // EnterWorld() // ---------------------------------------------------------------------- function EnterWorld() { PutInWorld(true); } // ---------------------------------------------------------------------- // LeaveWorld() // ---------------------------------------------------------------------- function LeaveWorld() { PutInWorld(false); } // ---------------------------------------------------------------------- // PutInWorld() // ---------------------------------------------------------------------- function PutInWorld(bool bEnter) { if (bInWorld && !bEnter) { bInWorld = false; GotoState('Idle'); bHidden = true; bDetectable = false; WorldPosition = Location; bWorldCollideActors = bCollideActors; bWorldBlockActors = bBlockActors; bWorldBlockPlayers = bBlockPlayers; SetCollision(false, false, false); bCollideWorld = false; SetPhysics(PHYS_None); KillShadow(); SetLocation(Location+vect(0,0,20000)); // move it out of the way } else if (!bInWorld && bEnter) { bInWorld = true; bHidden = Default.bHidden; bDetectable = Default.bDetectable; SetLocation(WorldPosition); SetCollision(bWorldCollideActors, bWorldBlockActors, bWorldBlockPlayers); bCollideWorld = Default.bCollideWorld; SetMovementPhysics(); CreateShadow(); FollowOrders(); } } // ---------------------------------------------------------------------- // MakePawnIgnored() // ---------------------------------------------------------------------- function MakePawnIgnored(bool bNewIgnore) { if (bNewIgnore) { bIgnore = bNewIgnore; // to restore original behavior, uncomment the next line //bDetectable = !bNewIgnore; } else { bIgnore = Default.bIgnore; // to restore original behavior, uncomment the next line //bDetectable = Default.bDetectable; } } // ---------------------------------------------------------------------- // EnableCollision() [for sitting state] // ---------------------------------------------------------------------- function EnableCollision(bool bSet) { EnableShadow(bSet); if (bSet) SetCollision(Default.bCollideActors, Default.bBlockActors, Default.bBlockPlayers); else SetCollision(True, False, True); } // ---------------------------------------------------------------------- // SetBasedPawnSize() // ---------------------------------------------------------------------- function bool SetBasedPawnSize(float newRadius, float newHeight) { local float oldRadius, oldHeight; local bool bSuccess; local vector centerDelta; local float deltaEyeHeight; if (newRadius < 0) newRadius = 0; if (newHeight < 0) newHeight = 0; oldRadius = CollisionRadius; oldHeight = CollisionHeight; if ((oldRadius == newRadius) && (oldHeight == newHeight)) return true; centerDelta = vect(0, 0, 1)*(newHeight-oldHeight); deltaEyeHeight = GetDefaultCollisionHeight() - Default.BaseEyeHeight; bSuccess = false; if ((newHeight <= CollisionHeight) && (newRadius <= CollisionRadius)) // shrink { SetCollisionSize(newRadius, newHeight); if (Move(centerDelta)) bSuccess = true; else SetCollisionSize(oldRadius, oldHeight); } else { if (Move(centerDelta)) { SetCollisionSize(newRadius, newHeight); bSuccess = true; } } if (bSuccess) { PrePivotOffset = vect(0, 0, 1)*(GetDefaultCollisionHeight()-newHeight); PrePivot -= centerDelta; DesiredPrePivot -= centerDelta; BaseEyeHeight = newHeight - deltaEyeHeight; } return (bSuccess); } // ---------------------------------------------------------------------- // ResetBasedPawnSize() // ---------------------------------------------------------------------- function ResetBasedPawnSize() { SetBasedPawnSize(Default.CollisionRadius, GetDefaultCollisionHeight()); } // ---------------------------------------------------------------------- // GetDefaultCollisionHeight() // ---------------------------------------------------------------------- function float GetDefaultCollisionHeight() { return (Default.CollisionHeight-4.5); } // ---------------------------------------------------------------------- // GetCrouchHeight() // ---------------------------------------------------------------------- function float GetCrouchHeight() { return (Default.CollisionHeight*0.65); } // ---------------------------------------------------------------------- // GetSitHeight() // ---------------------------------------------------------------------- function float GetSitHeight() { return (GetDefaultCollisionHeight()+(BaseAssHeight*0.5)); } // ---------------------------------------------------------------------- // IsPointInCylinder() // ---------------------------------------------------------------------- function bool IsPointInCylinder(Actor cylinder, Vector point, optional float extraRadius, optional float extraHeight) { local bool bPointInCylinder; local float tempX, tempY, tempRad; tempX = cylinder.Location.X - point.X; tempX *= tempX; tempY = cylinder.Location.Y - point.Y; tempY *= tempY; tempRad = cylinder.CollisionRadius + extraRadius; tempRad *= tempRad; bPointInCylinder = false; if (tempX+tempY < tempRad) if (Abs(cylinder.Location.Z - point.Z) < (cylinder.CollisionHeight+extraHeight)) bPointInCylinder = true; return (bPointInCylinder); } // ---------------------------------------------------------------------- // StartFalling() // ---------------------------------------------------------------------- function StartFalling(Name resumeState, optional Name resumeLabel) { SetNextState(resumeState, resumeLabel); GotoState('FallingState'); } // ---------------------------------------------------------------------- // GetNextWaypoint() // ---------------------------------------------------------------------- function Actor GetNextWaypoint(Actor destination) { local Actor moveTarget; if (destination == None) moveTarget = None; else if (ActorReachable(destination)) moveTarget = destination; else moveTarget = FindPathToward(destination); return (moveTarget); } // ---------------------------------------------------------------------- // GetNextVector() // ---------------------------------------------------------------------- function bool GetNextVector(Actor destination, out vector outVect) { local bool bValid; local rotator rot; local float dist; local float maxDist; bValid = true; if (destination != None) { maxDist = 64; rot = Rotator(destination.Location - Location); dist = VSize(destination.Location - Location); if (dist < maxDist) outVect = destination.Location; else if (!AIDirectionReachable(Location, rot.Yaw, rot.Pitch, 0, maxDist, outVect)) bValid = false; } else bValid = false; return (bValid); } // ---------------------------------------------------------------------- // FindOrderActor() // ---------------------------------------------------------------------- function FindOrderActor() { if (Orders == 'Attacking') OrderActor = FindTaggedActor(OrderTag, true, Class'Pawn'); else OrderActor = FindTaggedActor(OrderTag); } // ---------------------------------------------------------------------- // FindTaggedActor() // ---------------------------------------------------------------------- function Actor FindTaggedActor(Name actorTag, optional bool bRandom, optional Class<Actor> tagClass) { local float dist; local float bestDist; local actor bestActor; local actor tempActor; bestActor = None; bestDist = 1000000; if (tagClass == None) tagClass = Class'Actor'; // if no tag, then assume the player is the target if (actorTag == '') bestActor = GetPlayerPawn(); else { foreach AllActors(tagClass, tempActor, actorTag) { if (tempActor != self) { dist = VSize(tempActor.Location - Location); if (bRandom) dist *= FRand()*0.6+0.7; // +/- 30% if ((bestActor == None) || (dist < bestDist)) { bestActor = tempActor; bestDist = dist; } } } } return bestActor; } // ---------------------------------------------------------------------- // HandleEnemy() // ---------------------------------------------------------------------- function HandleEnemy() { SetState('HandlingEnemy', 'Begin'); } // ---------------------------------------------------------------------- // HandleSighting() // ---------------------------------------------------------------------- function HandleSighting(Pawn pawnSighted) { SetSeekLocation(pawnSighted, pawnSighted.Location, SEEKTYPE_Sight); GotoState('Seeking'); } // ---------------------------------------------------------------------- // FollowOrders() // ---------------------------------------------------------------------- function FollowOrders(optional bool bDefer) { local bool bSetEnemy; local bool bUseOrderActor; if (Orders != '') { if ((Orders == 'Fleeing') || (Orders == 'Attacking')) { bSetEnemy = true; bUseOrderActor = true; } else if ((Orders == 'WaitingFor') || (Orders == 'GoingTo') || (Orders == 'RunningTo') || (Orders == 'Following') || (Orders == 'Sitting') || (Orders == 'Shadowing') || (Orders == 'DebugFollowing') || (Orders == 'DebugPathfinding')) { bSetEnemy = false; bUseOrderActor = true; } else { bSetEnemy = false; bUseOrderActor = false; } if (bUseOrderActor) { FindOrderActor(); if (bSetEnemy) SetEnemy(Pawn(OrderActor), 0, true); } if (bDefer) // hack SetState(Orders); else GotoState(Orders); } else { if (bDefer) SetState('Wandering'); else GotoState('Wandering'); } } // ---------------------------------------------------------------------- // ResetConvOrders() // ---------------------------------------------------------------------- function ResetConvOrders() { ConvOrders = ''; ConvOrderTag = ''; } // ---------------------------------------------------------------------- // GenerateTotalHealth() // // this will calculate a weighted average of all of the body parts // and put that value in the generic Health // NOTE: head and torso are both critical // ---------------------------------------------------------------------- function GenerateTotalHealth() { local float limbDamage, headDamage, torsoDamage; if (!bInvincible) { // Scoring works as follows: // Disabling the head (100 points damage) will kill you. // Disabling the torso (100 points damage) will kill you. // Disabling 2 1/2 limbs (250 points damage) will kill you. // Combinations can also do you in -- 50 points damage to the head // and 125 points damage to the limbs, for example. // Note that this formula can produce numbers less than zero, so we'll clamp our // health value... // Compute total limb damage limbDamage = 0; if (Default.HealthLegLeft > 0) limbDamage += float(Default.HealthLegLeft-HealthLegLeft)/Default.HealthLegLeft; if (Default.HealthLegRight > 0) limbDamage += float(Default.HealthLegRight-HealthLegRight)/Default.HealthLegRight; if (Default.HealthArmLeft > 0) limbDamage += float(Default.HealthArmLeft-HealthArmLeft)/Default.HealthArmLeft; if (Default.HealthArmRight > 0) limbDamage += float(Default.HealthArmRight-HealthArmRight)/Default.HealthArmRight; limbDamage *= 0.4; // 2 1/2 limbs disabled == death // Compute total head damage headDamage = 0; if (Default.HealthHead > 0) headDamage = float(Default.HealthHead-HealthHead)/Default.HealthHead; // Compute total torso damage torsoDamage = 0; if (Default.HealthTorso > 0) torsoDamage = float(Default.HealthTorso-HealthTorso)/Default.HealthTorso; // Compute total health, relative to original health level Health = FClamp(Default.Health - ((limbDamage+headDamage+torsoDamage)*Default.Health), 0.0, Default.Health); } else { // Pawn is invincible - reset health to defaults HealthHead = Default.HealthHead; HealthTorso = Default.HealthTorso; HealthArmLeft = Default.HealthArmLeft; HealthArmRight = Default.HealthArmRight; HealthLegLeft = Default.HealthLegLeft; HealthLegRight = Default.HealthLegRight; Health = Default.Health; } } // ---------------------------------------------------------------------- // UpdatePoison() // ---------------------------------------------------------------------- function UpdatePoison(float deltaTime) { if ((Health <= 0) || bDeleteMe) // no more pain -- you're already dead! return; if (poisonCounter > 0) { poisonTimer += deltaTime; if (poisonTimer >= 2.0) // pain every two seconds { poisonTimer = 0; poisonCounter--; TakeDamage(poisonDamage, Poisoner, Location, vect(0,0,0), 'PoisonEffect'); } if ((poisonCounter <= 0) || (Health <= 0) || bDeleteMe) StopPoison(); } } // ---------------------------------------------------------------------- // StartPoison() // ---------------------------------------------------------------------- function StartPoison(int Damage, Pawn newPoisoner) { if ((Health <= 0) || bDeleteMe) // no more pain -- you're already dead! return; poisonCounter = 8; // take damage no more than eight times (over 16 seconds) poisonTimer = 0; // reset pain timer Poisoner = newPoisoner; if (poisonDamage < Damage) // set damage amount poisonDamage = Damage; } // ---------------------------------------------------------------------- // StopPoison() // ---------------------------------------------------------------------- function StopPoison() { poisonCounter = 0; poisonTimer = 0; poisonDamage = 0; Poisoner = None; } // ---------------------------------------------------------------------- // HasEnemyTimedOut() // ---------------------------------------------------------------------- function bool HasEnemyTimedOut() { if (EnemyTimeout > 0) { if (EnemyLastSeen > EnemyTimeout) return true; else return false; } else return false; } // ---------------------------------------------------------------------- // UpdateActorVisibility() // ---------------------------------------------------------------------- function UpdateActorVisibility(actor seeActor, float deltaSeconds, float checkTime, bool bCheckDir) { local bool bCanSee; CheckPeriod += deltaSeconds; if (CheckPeriod >= checkTime) { CheckPeriod = 0.0; if (seeActor != None) bCanSee = (AICanSee(seeActor, ComputeActorVisibility(seeActor), false, bCheckDir, true, true) > 0); else bCanSee = false; if (bCanSee) EnemyLastSeen = 0; else if (EnemyLastSeen <= 0) EnemyLastSeen = 0.01; } if (EnemyLastSeen > 0) EnemyLastSeen += deltaSeconds; } // ---------------------------------------------------------------------- // ComputeActorVisibility() // ---------------------------------------------------------------------- function float ComputeActorVisibility(actor seeActor) { local float visibility; if (seeActor.IsA('DeusExPlayer')) visibility = DeusExPlayer(seeActor).CalculatePlayerVisibility(self); else visibility = 1.0; return (visibility); } // ---------------------------------------------------------------------- // UpdateReactionLevel() [internal use only] // ---------------------------------------------------------------------- function UpdateReactionLevel(bool bRise, float deltaSeconds) { local float surpriseTime; // Handle surprise levels... if (bRise) { if (ReactionLevel < 1.0) { surpriseTime = SurprisePeriod; if (surpriseTime <= 0) surpriseTime = 0.00000001; ReactionLevel += deltaSeconds/surpriseTime; if (ReactionLevel > 1.0) ReactionLevel = 1.0; } } else { if (ReactionLevel > 0.0) { surpriseTime = 7.0; ReactionLevel -= deltaSeconds/surpriseTime; if (ReactionLevel <= 0.0) ReactionLevel = 0.0; } } } // ---------------------------------------------------------------------- // CheckCycle() [internal use only] // ---------------------------------------------------------------------- function Pawn CheckCycle() { local float attackPeriod; local float maxAttackPeriod; local float sustainPeriod; local float decayPeriod; local float minCutoff; local Pawn cycleEnemy; attackPeriod = 0.5; maxAttackPeriod = 4.5; sustainPeriod = 3.0; decayPeriod = 4.0; minCutoff = attackPeriod/maxAttackPeriod; cycleEnemy = None; if (CycleCumulative <= 0) // no enemies seen during this cycle { CycleTimer -= CyclePeriod; if (CycleTimer <= 0) { CycleTimer = 0; EnemyReadiness -= CyclePeriod/decayPeriod; if (EnemyReadiness < 0) EnemyReadiness = 0; } } else // I saw somebody! { CycleTimer = sustainPeriod; CycleCumulative *= 2; // hack if (CycleCumulative < minCutoff) CycleCumulative = minCutoff; else if (CycleCumulative > 1.0) CycleCumulative = 1.0; EnemyReadiness += CycleCumulative*CyclePeriod/attackPeriod; if (EnemyReadiness >= 1.0) { EnemyReadiness = 1.0; if (IsValidEnemy(CycleCandidate)) cycleEnemy = CycleCandidate; } else if (EnemyReadiness >= SightPercentage) if (IsValidEnemy(CycleCandidate)) HandleSighting(CycleCandidate); } CycleCumulative = 0; CyclePeriod = 0; CycleCandidate = None; CycleDistance = 0; return (cycleEnemy); } // ---------------------------------------------------------------------- // CheckEnemyPresence() // ---------------------------------------------------------------------- function bool CheckEnemyPresence(float deltaSeconds, bool bCheckPlayer, bool bCheckOther) { local int i; local int count; local int checked; local Pawn candidate; local float candidateDist; local DeusExPlayer playerCandidate; local bool bCanSee; local int lastCycle; local float visibility; local Pawn cycleEnemy; local bool bValid; local bool bPlayer; local float surpriseTime; local bool bValidEnemy; local bool bPotentialEnemy; local bool bCheck; bValid = false; bCanSee = false; if (bReactPresence && bLookingForEnemy && !bNoNegativeAlliances) { if (PotentialEnemyAlliance != '') bCheck = true; else { for (i=0; i<16; i++) if ((AlliancesEx[i].AllianceLevel < 0) || (AlliancesEx[i].AgitationLevel >= 1.0)) break; if (i < 16) bCheck = true; } if (bCheck) { bValid = true; CyclePeriod += deltaSeconds; count = 0; checked = 0; lastCycle = CycleIndex; foreach CycleActors(Class'Pawn', candidate, CycleIndex) { bValidEnemy = IsValidEnemy(candidate); if (!bValidEnemy && (PotentialEnemyTimer > 0)) if (PotentialEnemyAlliance == candidate.Alliance) bPotentialEnemy = true; if (bValidEnemy || bPotentialEnemy) { count++; bPlayer = candidate.IsA('PlayerPawn'); if ((bPlayer && bCheckPlayer) || (!bPlayer && bCheckOther)) { visibility = AICanSee(candidate, ComputeActorVisibility(candidate), true, true, true, true); if (visibility > 0) { if (bPotentialEnemy) // We can see the potential enemy; ergo, we hate him { IncreaseAgitation(candidate, 1.0); PotentialEnemyAlliance = ''; PotentialEnemyTimer = 0; bValidEnemy = IsValidEnemy(candidate); } if (bValidEnemy) { visibility += VisibilityThreshold; candidateDist = VSize(Location-candidate.Location); if ((CycleCandidate == None) || (CycleDistance > candidateDist)) { CycleCandidate = candidate; CycleDistance = candidateDist; } if (!bPlayer) CycleCumulative += 100000; // a bit of a hack... else CycleCumulative += visibility; } } } if (count >= 1) break; } checked++; if (checked > 20) // hacky hardcoded number break; } if (lastCycle >= CycleIndex) // have we cycled through all actors? { cycleEnemy = CheckCycle(); if (cycleEnemy != None) { SetDistressTimer(); SetEnemy(cycleEnemy, 0, true); bCanSee = true; } } } else bNoNegativeAlliances = True; } // Handle surprise levels... UpdateReactionLevel((EnemyReadiness>0)||(GetStateName()=='Seeking')||bDistressed, deltaSeconds); if (!bValid) { CycleCumulative = 0; CyclePeriod = 0; CycleCandidate = None; CycleDistance = 0; CycleTimer = 0; } return (bCanSee); } // ---------------------------------------------------------------------- // CheckBeamPresence // ---------------------------------------------------------------------- function bool CheckBeamPresence(float deltaSeconds) { local DeusExPlayer player; local Beam beamActor; local bool bReactToBeam; if (bReactPresence && bLookingForEnemy && (BeamCheckTimer <= 0) && (LastRendered() < 5.0)) { BeamCheckTimer = 1.0; player = DeusExPlayer(GetPlayerPawn()); if (player != None) { bReactToBeam = false; if (IsValidEnemy(player)) { foreach RadiusActors(Class'Beam', beamActor, 1200) { if ((beamActor.Owner == player) && (beamActor.LightType != LT_None) && (beamActor.LightBrightness > 32)) { if (VSize(beamActor.Location - Location) < (beamActor.LightRadius+1)*25) bReactToBeam = true; else { if (AICanSee(beamActor, , false, true, false, false) > 0) { if (FastTrace(beamActor.Location, Location+vect(0,0,1)*BaseEyeHeight)) bReactToBeam = true; } } } if (bReactToBeam) break; } } if (bReactToBeam) HandleSighting(player); } } } // ---------------------------------------------------------------------- // CheckCarcassPresence() // ---------------------------------------------------------------------- function bool CheckCarcassPresence(float deltaSeconds) { local Actor carcass; local Name CarcassName; local int lastCycle; local DeusExCarcass body; local DeusExPlayer player; local float visibility; local Name KillerAlliance; local Name killedAlliance; local Pawn killer; local Pawn bestKiller; local float dist; local float bestDist; local float maxCarcassDist; local int maxCarcassCount; if (bFearCarcass && !bHateCarcass && !bReactCarcass) // Major hack! maxCarcassCount = 1; else maxCarcassCount = ArrayCount(Carcasses); //if ((bHateCarcass || bReactCarcass || bFearCarcass) && bLookingForCarcass && (CarcassTimer <= 0)) if ((bHateCarcass || bReactCarcass || bFearCarcass) && (NumCarcasses < maxCarcassCount)) { maxCarcassDist = 1200; if (CarcassCheckTimer <= 0) { CarcassCheckTimer = 0.1; carcass = None; lastCycle = BodyIndex; foreach CycleActors(Class'DeusExCarcass', body, BodyIndex) { if (body.Physics != PHYS_Falling) { if (VSize(body.Location-Location) < maxCarcassDist) { if (GetCarcassData(body, KillerAlliance, killedAlliance, CarcassName, true)) { visibility = AICanSee(body, ComputeActorVisibility(body), true, true, true, true); if (visibility > 0) carcass = body; break; } } } } if (lastCycle >= BodyIndex) { if (carcass == None) { player = DeusExPlayer(GetPlayerPawn()); if (player != None) { if (VSize(player.Location-Location) < maxCarcassDist) { if (GetCarcassData(player, KillerAlliance, killedAlliance, CarcassName, true)) { visibility = AICanSee(player, ComputeActorVisibility(player), true, true, true, true); if (visibility > 0) carcass = player; } } } } } if (carcass != None) { CarcassTimer = 120; AddCarcass(CarcassName); if (bLookingForCarcass) { if (KillerAlliance == 'Player') killer = GetPlayerPawn(); else { bestKiller = None; bestDist = 0; foreach AllActors(Class'Pawn', killer) // hack { if (killer.Alliance == KillerAlliance) { dist = VSize(killer.Location - Location); if ((bestKiller == None) || (bestDist > dist)) { bestKiller = killer; bestDist = dist; } } } killer = bestKiller; } if (bHateCarcass) { PotentialEnemyAlliance = KillerAlliance; PotentialEnemyTimer = 15.0; bNoNegativeAlliances = false; } if (bFearCarcass) IncreaseFear(killer, 2.0); if (bFearCarcass && IsFearful() && !IsValidEnemy(killer)) { SetDistressTimer(); SetEnemy(killer, , true); GotoState('Fleeing'); } else { SetDistressTimer(); SetSeekLocation(killer, carcass.Location, SEEKTYPE_Carcass); HandleEnemy(); } } } } } } // ---------------------------------------------------------------------- // AddProjectileToList() // ---------------------------------------------------------------------- function AddProjectileToList(out NearbyProjectileList projList, DeusExProjectile proj, vector projPos, float dist, float range) { local int count; local int pos; local int bestPos; local float worstDist; bestPos = -1; worstDist = dist; pos = 0; while (pos < ArrayCount(projList.list)) { if (projList.list[pos].projectile == None) { bestPos = pos; break; // short-circuit loop } else { if (worstDist < projList.list[pos].dist) { worstDist = projList.list[pos].dist; bestPos = pos; } } pos++; } if (bestPos >= 0) { projList.list[bestPos].projectile = proj; projList.list[bestPos].location = projPos; projList.list[bestPos].dist = dist; projList.list[bestPos].range = range; } } // ---------------------------------------------------------------------- // IsProjectileDangerous() // ---------------------------------------------------------------------- function bool IsProjectileDangerous(DeusExProjectile projectile) { local bool bEvil; if (projectile.IsA('Cloud')) bEvil = true; else if (projectile.IsA('ThrownProjectile')) { if (projectile.IsA('SpyBot')) bEvil = false; else if ((ThrownProjectile(projectile) != None) && (ThrownProjectile(projectile).bProximityTriggered)) bEvil = false; else bEvil = true; } else bEvil = false; return (bEvil); } // ---------------------------------------------------------------------- // GetProjectileList() // ---------------------------------------------------------------------- function int GetProjectileList(out NearbyProjectileList projList, vector Location) { local float dist; local int count; local DeusExProjectile curProj; local ThrownProjectile throwProj; local Cloud cloudProj; local vector HitNormal, HitLocation; local vector extent; local vector traceEnd; local Actor hitActor; local float range; local vector pos; local float time; local float maxTime; local float elasticity; local int i; local bool bValid; for (i=0; i<ArrayCount(projList.list); i++) projList.list[i].projectile = None; projList.center = Location; maxTime = 2.0; foreach RadiusActors(Class'DeusExProjectile', curProj, 1000) { if (IsProjectileDangerous(curProj)) { throwProj = ThrownProjectile(curProj); cloudProj = Cloud(curProj); extent = vect(1,1,0)*curProj.CollisionRadius; extent.Z = curProj.CollisionHeight; range = VSize(extent); if (curProj.bExplodes) if (range < curProj.blastRadius) range = curProj.blastRadius; if (cloudProj != None) if (range < cloudProj.cloudRadius) range = cloudProj.cloudRadius; range += CollisionRadius+60; if (throwProj != None) elasticity = throwProj.Elasticity; else elasticity = 0.2; bValid = true; if (throwProj != None) if (throwProj.bProximityTriggered) // HACK!!! bValid = false; if (((curProj.Physics == PHYS_Falling) || (curProj.Physics == PHYS_Projectile) || (curProj.Physics == PHYS_None)) && bValid) { pos = curProj.Location; dist = VSize(Location - curProj.Location); AddProjectileToList(projList, curProj, pos, dist, range); if (curProj.Physics == PHYS_Projectile) { traceEnd = curProj.Location + curProj.Velocity*maxTime; hitActor = Trace(HitLocation, HitNormal, traceEnd, curProj.Location, true, extent); if (hitActor == None) pos = traceEnd; else pos = HitLocation; dist = VSize(Location - pos); AddProjectileToList(projList, curProj, pos, dist, range); } else if (curProj.Physics == PHYS_Falling) { time = ParabolicTrace(pos, curProj.Velocity, curProj.Location, true, extent, maxTime, elasticity, curProj.bBounce, 60); if (time > 0) { dist = VSize(Location - pos); AddProjectileToList(projList, curProj, pos, dist, range); } } } } } count = 0; for (i=0; i<ArrayCount(projList.list); i++) if (projList.list[i].projectile != None) count++; return (count); } // ---------------------------------------------------------------------- // IsLocationDangerous() // ---------------------------------------------------------------------- function bool IsLocationDangerous(NearbyProjectileList projList, vector Location) { local bool bDanger; local int i; local float dist; bDanger = false; for (i=0; i<ArrayCount(projList.list); i++) { if (projList.list[i].projectile == None) break; if (projList.center == Location) dist = projList.list[i].dist; else dist = VSize(projList.list[i].location - Location); if (dist < projList.list[i].range) { bDanger = true; break; } } return (bDanger); } // ---------------------------------------------------------------------- // ComputeAwayVector() // ---------------------------------------------------------------------- function vector ComputeAwayVector(NearbyProjectileList projList) { local vector awayVect; local vector tempVect; local rotator tempRot; local int i; local float dist; local int yaw; local int absYaw; local int bestYaw; local NavigationPoint navPoint; local NavigationPoint bestPoint; local float segmentDist; segmentDist = GroundSpeed*0.5; awayVect = vect(0, 0, 0); for (i=0; i<ArrayCount(projList.list); i++) { if ((projList.list[i].projectile != None) && (projList.list[i].dist < projList.list[i].range)) { tempVect = projList.list[i].location - projList.center; if (projList.list[i].dist > 0) tempVect /= projList.list[i].dist; else tempVect = VRand(); awayVect -= tempVect; } } if (awayVect != vect(0, 0, 0)) { awayVect += Normal(Velocity*vect(1,1,0))*0.9; // bias to direction already running yaw = Rotator(awayVect).Yaw; bestPoint = None; foreach ReachablePathnodes(Class'NavigationPoint', navPoint, None, dist) { tempRot = Rotator(navPoint.Location - Location); absYaw = (tempRot.Yaw - Yaw) & 65535; if (absYaw > 32767) absYaw -= 65536; absYaw = Abs(absYaw); if ((bestPoint == None) || (bestYaw > absYaw)) { bestPoint = navPoint; bestYaw = absYaw; } } if (bestPoint != None) awayVect = bestPoint.Location-Location; else { tempRot = Rotator(awayVect); tempRot.Pitch += Rand(7282)-3641; // +/- 20 degrees tempRot.Yaw += Rand(7282)-3641; // +/- 20 degrees awayVect = Vector(tempRot)*segmentDist; } } else awayVect = VRand()*segmentDist; return (awayVect); } // ---------------------------------------------------------------------- // SetupWeapon() // ---------------------------------------------------------------------- function SetupWeapon(bool bDrawWeapon, optional bool bForce) { if (bKeepWeaponDrawn && !bForce) bDrawWeapon = true; if (ShouldDropWeapon()) DropWeapon(); else if (bDrawWeapon) { // if (Weapon == None) SwitchToBestWeapon(); } else SetWeapon(None); } // ---------------------------------------------------------------------- // DropWeapon() // ---------------------------------------------------------------------- function DropWeapon() { local DeusExWeapon dxWeapon; local Weapon oldWeapon; if (Weapon != None) { dxWeapon = DeusExWeapon(Weapon); if ((dxWeapon == None) || !dxWeapon.bNativeAttack) { oldWeapon = Weapon; SetWeapon(None); oldWeapon.DropFrom(Location); } } } // ---------------------------------------------------------------------- // SetWeapon() // ---------------------------------------------------------------------- function SetWeapon(Weapon newWeapon) { if (Weapon == newWeapon) { if (Weapon != None) { if (Weapon.IsInState('DownWeapon')) Weapon.BringUp(); Weapon.SetDefaultDisplayProperties(); } if (Inventory != None) Inventory.ChangedWeapon(); PendingWeapon = None; return; } PlayWeaponSwitch(newWeapon); if (Weapon != None) { Weapon.SetDefaultDisplayProperties(); Weapon.PutDown(); } Weapon = newWeapon; if (Inventory != None) Inventory.ChangedWeapon(); if (Weapon != None) Weapon.BringUp(); PendingWeapon = None; } // ---------------------------------------------------------------------- // ReactToInjury() // ---------------------------------------------------------------------- function ReactToInjury(Pawn instigatedBy, Name damageType, EHitLocation hitPos) { local Name currentState; local bool bHateThisInjury; local bool bFearThisInjury; if ((health > 0) && (instigatedBy != None) && (bLookingForInjury || bLookingForIndirectInjury)) { currentState = GetStateName(); bHateThisInjury = ShouldReactToInjuryType(damageType, bHateInjury, bHateIndirectInjury); bFearThisInjury = ShouldReactToInjuryType(damageType, bFearInjury, bFearIndirectInjury); if (bHateThisInjury) IncreaseAgitation(instigatedBy); if (bFearThisInjury) IncreaseFear(instigatedBy, 2.0); if (SetEnemy(instigatedBy)) { SetDistressTimer(); SetNextState('HandlingEnemy'); } else if (bFearThisInjury && IsFearful()) { SetDistressTimer(); SetEnemy(instigatedBy, , true); SetNextState('Fleeing'); } else { // if (instigatedBy.bIsPlayer) // ReactToFutz(); SetNextState(currentState); } GotoDisabledState(damageType, hitPos); } } // ---------------------------------------------------------------------- // TakeHit() // ---------------------------------------------------------------------- function TakeHit(EHitLocation hitPos) { if (hitPos != HITLOC_None) { PlayTakingHit(hitPos); GotoState('TakingHit'); } else GotoNextState(); } // ---------------------------------------------------------------------- // ComputeFallDirection() // ---------------------------------------------------------------------- function ComputeFallDirection(float totalTime, int numFrames, out vector moveDir, out float stopTime) { // Determine direction, and how long to slide if (AnimSequence == 'DeathFront') { moveDir = Vector(DesiredRotation) * Default.CollisionRadius*0.75; if (numFrames > 5) stopTime = totalTime * ((numFrames-5)/float(numFrames)); else stopTime = totalTime * 0.5; } else if (AnimSequence == 'DeathBack') { moveDir = -Vector(DesiredRotation) * Default.CollisionRadius*0.75; if (numFrames > 5) stopTime = totalTime * ((numFrames-5)/float(numFrames)); else stopTime = totalTime * 0.9; } } // ---------------------------------------------------------------------- // WillTakeStompDamage() // ---------------------------------------------------------------------- function bool WillTakeStompDamage(Actor stomper) { return true; } // ---------------------------------------------------------------------- // DrawShield() // ---------------------------------------------------------------------- function DrawShield() { local EllipseEffect shield; shield = Spawn(class'EllipseEffect', Self,, Location, Rotation); if (shield != None) shield.SetBase(Self); } // ---------------------------------------------------------------------- // StandUp() // ---------------------------------------------------------------------- function StandUp(optional bool bInstant) { local vector placeToStand; if (bSitting) { bSitInterpolation = false; bSitting = false; EnableCollision(true); SetBase(None); SetPhysics(PHYS_Falling); ResetBasedPawnSize(); if (!bInstant && (SeatActor != None) && IsOverlapping(SeatActor)) { bStandInterpolation = true; remainingStandTime = 0.3; StandRate = (Vector(SeatActor.Rotation+Rot(0, -16384, 0))*CollisionRadius) / remainingStandTime; } else StopStanding(); } if (SeatActor != None) { if (SeatActor.sittingActor[seatSlot] == self) SeatActor.sittingActor[seatSlot] = None; SeatActor = None; } if (bDancing) bDancing = false; } // ---------------------------------------------------------------------- // StopStanding() // ---------------------------------------------------------------------- function StopStanding() { if (bStandInterpolation) { bStandInterpolation = false; remainingStandTime = 0; if (Physics == PHYS_Flying) SetPhysics(PHYS_Falling); } } // ---------------------------------------------------------------------- // UpdateStanding() // ---------------------------------------------------------------------- function UpdateStanding(float deltaSeconds) { local float delta; local vector newPos; if (bStandInterpolation) { if ((Physics == PHYS_Walking) && (Acceleration != vect(0,0,0))) // the bastard's walking now StopStanding(); else { if ((deltaSeconds < remainingStandTime) && (remainingStandTime > 0)) { delta = deltaSeconds; remainingStandTime -= deltaSeconds; } else { delta = remainingStandTime; StopStanding(); } newPos = StandRate*delta; Move(newPos); } } } // ---------------------------------------------------------------------- // JumpOutOfWater() // ---------------------------------------------------------------------- function JumpOutOfWater(vector jumpDir) { Falling(); Velocity = jumpDir * WaterSpeed; Acceleration = jumpDir * AccelRate; velocity.Z = 380; //set here so physics uses this for remainder of tick PlayFalling(); bUpAndOut = true; } // ---------------------------------------------------------------------- // SupportActor() // // Modified from DeusExDecoration.uc // Called when something lands on us // ---------------------------------------------------------------------- function SupportActor(Actor standingActor) { local vector newVelocity; local float angle; local float zVelocity; local float baseMass; local float standingMass; local vector damagePoint; local float damage; standingMass = FMax(1, standingActor.Mass); baseMass = FMax(1, Mass); if ((Physics == PHYS_Swimming) && Region.Zone.bWaterZone) { newVelocity = standingActor.Velocity; newVelocity *= 0.5*standingMass/baseMass; AddVelocity(newVelocity); } else { zVelocity = standingActor.Velocity.Z; damagePoint = Location + vect(0,0,1)*(CollisionHeight-1); damage = (1 - (standingMass/baseMass) * (zVelocity/100)); // Have we been stomped? if ((zVelocity*standingMass < -7500) && (damage > 0) && WillTakeStompDamage(standingActor)) TakeDamage(damage, standingActor.Instigator, damagePoint, 0.2*standingActor.Velocity, 'stomped'); } // Bounce the actor off the pawn angle = FRand()*Pi*2; newVelocity.X = cos(angle); newVelocity.Y = sin(angle); newVelocity.Z = 0; newVelocity *= FRand()*25 + 25; newVelocity += standingActor.Velocity; newVelocity.Z = 50; standingActor.Velocity = newVelocity; standingActor.SetPhysics(PHYS_Falling); } // ---------------------------------------------------------------------- // SpawnCarcass() // ---------------------------------------------------------------------- function Carcass SpawnCarcass() { local DeusExCarcass carc; local vector loc; local Inventory item, nextItem; local FleshFragment chunk; local int i; local float size; // if we really got blown up good, gib us and don't display a carcass if ((Health < -100) && !IsA('Robot')) { size = (CollisionRadius + CollisionHeight) / 2; if (size > 10.0) { for (i=0; i<size/4.0; i++) { loc.X = (1-2*FRand()) * CollisionRadius; loc.Y = (1-2*FRand()) * CollisionRadius; loc.Z = (1-2*FRand()) * CollisionHeight; loc += Location; chunk = spawn(class'FleshFragment', None,, loc); if (chunk != None) { chunk.DrawScale = size / 25; chunk.SetCollisionSize(chunk.CollisionRadius / chunk.DrawScale, chunk.CollisionHeight / chunk.DrawScale); chunk.bFixedRotationDir = True; chunk.RotationRate = RotRand(False); } } } return None; } // spawn the carcass carc = DeusExCarcass(Spawn(CarcassType)); if ( carc != None ) { if (bStunned) carc.bNotDead = True; carc.Initfor(self); // move it down to the floor loc = Location; loc.z -= Default.CollisionHeight; loc.z += carc.Default.CollisionHeight; carc.SetLocation(loc); carc.Velocity = Velocity; carc.Acceleration = Acceleration; // give the carcass the pawn's inventory if we aren't an animal or robot if (!IsA('Animal') && !IsA('Robot')) { if (Inventory != None) { do { item = Inventory; nextItem = item.Inventory; DeleteInventory(item); if ((DeusExWeapon(item) != None) && (DeusExWeapon(item).bNativeAttack)) item.Destroy(); else carc.AddInventory(item); item = nextItem; } until (item == None); } } } return carc; } // ---------------------------------------------------------------------- // FilterDamageType() // ---------------------------------------------------------------------- function bool FilterDamageType(Pawn instigatedBy, Vector hitLocation, Vector offset, Name damageType) { // Special cases for certain damage types if (damageType == 'HalonGas') if (bOnFire) ExtinguishFire(); if (damageType == 'EMP') { CloakEMPTimer += 10; // hack - replace with skill-based value if (CloakEMPTimer > 20) CloakEMPTimer = 20; EnableCloak(bCloakOn); return false; } return true; } // ---------------------------------------------------------------------- // ModifyDamage() // ---------------------------------------------------------------------- function float ModifyDamage(int Damage, Pawn instigatedBy, Vector hitLocation, Vector offset, Name damageType) { local int actualDamage; local float headOffsetZ, headOffsetY, armOffset; actualDamage = Damage; // calculate our hit extents headOffsetZ = CollisionHeight * 0.7; headOffsetY = CollisionRadius * 0.3; armOffset = CollisionRadius * 0.35; // if the pawn is stunned, damage is 4X if (bStunned) actualDamage *= 4; // if the pawn is hit from behind at point-blank range, he is killed instantly else if (offset.x < 0) if ((instigatedBy != None) && (VSize(instigatedBy.Location - Location) < 64)) actualDamage *= 10; actualDamage = Level.Game.ReduceDamage(actualDamage, DamageType, self, instigatedBy); if (ReducedDamageType == 'All') //God mode actualDamage = 0; else if (Inventory != None) //then check if carrying armor actualDamage = Inventory.ReduceDamage(actualDamage, DamageType, HitLocation); // gas, EMP and nanovirus do no damage if (damageType == 'TearGas' || damageType == 'EMP' || damageType == 'NanoVirus') actualDamage = 0; return actualDamage; } // ---------------------------------------------------------------------- // ShieldDamage() // ---------------------------------------------------------------------- function float ShieldDamage(Name damageType) { return 1.0; } // ---------------------------------------------------------------------- // ImpartMomentum() // ---------------------------------------------------------------------- function ImpartMomentum(Vector momentum, Pawn instigatedBy) { if (Physics == PHYS_None) SetMovementPhysics(); if (Physics == PHYS_Walking) momentum.Z = 0.4 * VSize(momentum); if ( instigatedBy == self ) momentum *= 0.6; momentum = momentum/Mass; AddVelocity( momentum ); } // ---------------------------------------------------------------------- // AddVelocity() // ---------------------------------------------------------------------- function AddVelocity(Vector momentum) { if (VSize(momentum) > 0.001) Super.AddVelocity(momentum); } // ---------------------------------------------------------------------- // CanShowPain() // ---------------------------------------------------------------------- function bool CanShowPain() { if (bShowPain && (TakeHitTimer <= 0)) return true; else return false; } // ---------------------------------------------------------------------- // IsPrimaryDamageType() // ---------------------------------------------------------------------- function bool IsPrimaryDamageType(name damageType) { local bool bPrimary; switch (damageType) { case 'Exploded': case 'TearGas': case 'HalonGas': case 'PoisonGas': case 'PoisonEffect': case 'Radiation': case 'EMP': case 'Drowned': case 'NanoVirus': bPrimary = false; break; case 'Stunned': case 'KnockedOut': case 'Burned': case 'Flamed': case 'Poison': case 'Shot': case 'Sabot': default: bPrimary = true; break; } return (bPrimary); } // ---------------------------------------------------------------------- // ShouldReactToInjuryType() // ---------------------------------------------------------------------- function bool ShouldReactToInjuryType(name damageType, bool bHatePrimary, bool bHateSecondary) { local bool bIsPrimary; bIsPrimary = IsPrimaryDamageType(damageType); if ((bHatePrimary && bIsPrimary) || (bHateSecondary && !bIsPrimary)) return true; else return false; } // ---------------------------------------------------------------------- // HandleDamage() // ---------------------------------------------------------------------- function EHitLocation HandleDamage(int actualDamage, Vector hitLocation, Vector offset, name damageType) { local EHitLocation hitPos; local float headOffsetZ, headOffsetY, armOffset; // calculate our hit extents headOffsetZ = CollisionHeight * 0.7; headOffsetY = CollisionRadius * 0.3; armOffset = CollisionRadius * 0.35; hitPos = HITLOC_None; if (actualDamage > 0) { if (offset.z > headOffsetZ) // head { // narrow the head region if ((Abs(offset.x) < headOffsetY) || (Abs(offset.y) < headOffsetY)) { // don't allow headshots with stunning weapons if ((damageType == 'Stunned') || (damageType == 'KnockedOut')) HealthHead -= actualDamage; else HealthHead -= actualDamage * 8; if (offset.x < 0.0) hitPos = HITLOC_HeadBack; else hitPos = HITLOC_HeadFront; } else // sides of head treated as torso { HealthTorso -= actualDamage * 2; if (offset.x < 0.0) hitPos = HITLOC_TorsoBack; else hitPos = HITLOC_TorsoFront; } } else if (offset.z < 0.0) // legs { if (offset.y > 0.0) { HealthLegRight -= actualDamage * 2; if (offset.x < 0.0) hitPos = HITLOC_RightLegBack; else hitPos = HITLOC_RightLegFront; } else { HealthLegLeft -= actualDamage * 2; if (offset.x < 0.0) hitPos = HITLOC_LeftLegBack; else hitPos = HITLOC_LeftLegFront; } // if this part is already dead, damage the adjacent part if ((HealthLegRight < 0) && (HealthLegLeft > 0)) { HealthLegLeft += HealthLegRight; HealthLegRight = 0; } else if ((HealthLegLeft < 0) && (HealthLegRight > 0)) { HealthLegRight += HealthLegLeft; HealthLegLeft = 0; } if (HealthLegLeft < 0) { HealthTorso += HealthLegLeft; HealthLegLeft = 0; } if (HealthLegRight < 0) { HealthTorso += HealthLegRight; HealthLegRight = 0; } } else // arms and torso { if (offset.y > armOffset) { HealthArmRight -= actualDamage * 2; if (offset.x < 0.0) hitPos = HITLOC_RightArmBack; else hitPos = HITLOC_RightArmFront; } else if (offset.y < -armOffset) { HealthArmLeft -= actualDamage * 2; if (offset.x < 0.0) hitPos = HITLOC_LeftArmBack; else hitPos = HITLOC_LeftArmFront; } else { HealthTorso -= actualDamage * 2; if (offset.x < 0.0) hitPos = HITLOC_TorsoBack; else hitPos = HITLOC_TorsoFront; } // if this part is already dead, damage the adjacent part if (HealthArmLeft < 0) { HealthTorso += HealthArmLeft; HealthArmLeft = 0; } if (HealthArmRight < 0) { HealthTorso += HealthArmRight; HealthArmRight = 0; } } } GenerateTotalHealth(); return hitPos; } // ---------------------------------------------------------------------- // TakeDamageBase() // ---------------------------------------------------------------------- function TakeDamageBase(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType, bool bPlayAnim) { local int actualDamage; local Vector offset; local float origHealth; local EHitLocation hitPos; local float shieldMult; // use the hitlocation to determine where the pawn is hit // transform the worldspace hitlocation into objectspace // in objectspace, remember X is front to back // Y is side to side, and Z is top to bottom offset = (hitLocation - Location) << Rotation; if (!CanShowPain()) bPlayAnim = false; // Prevent injury if the NPC is intangible if (!bBlockActors && !bBlockPlayers && !bCollideActors) return; // No damage + no damage type = no reaction if ((Damage <= 0) && (damageType == 'None')) return; // Block certain damage types; perform special ops on others if (!FilterDamageType(instigatedBy, hitLocation, offset, damageType)) return; // Impart momentum ImpartMomentum(momentum, instigatedBy); actualDamage = ModifyDamage(Damage, instigatedBy, hitLocation, offset, damageType); if (actualDamage > 0) { shieldMult = ShieldDamage(damageType); if (shieldMult > 0) actualDamage = Max(int(actualDamage*shieldMult), 1); else actualDamage = 0; if (shieldMult < 1.0) DrawShield(); } origHealth = Health; hitPos = HandleDamage(actualDamage, hitLocation, offset, damageType); if (!bPlayAnim || (actualDamage <= 0)) hitPos = HITLOC_None; if (bCanBleed) if ((damageType != 'Stunned') && (damageType != 'TearGas') && (damageType != 'HalonGas') && (damageType != 'PoisonGas') && (damageType != 'Radiation') && (damageType != 'EMP') && (damageType != 'NanoVirus') && (damageType != 'Drowned') && (damageType != 'KnockedOut') && (damageType != 'Poison') && (damageType != 'PoisonEffect')) bleedRate += (origHealth-Health)/(0.3*Default.Health); // 1/3 of default health = bleed profusely if (CarriedDecoration != None) DropDecoration(); if ((actualDamage > 0) && (damageType == 'Poison')) StartPoison(Damage, instigatedBy); if (Health <= 0) { ClearNextState(); //PlayDeathHit(actualDamage, hitLocation, damageType); if ( actualDamage > mass ) Health = -1 * actualDamage; SetEnemy(instigatedBy, 0, true); // gib us if we get blown up if (DamageType == 'Exploded') Health = -10000; else Health = -1; Died(instigatedBy, damageType, HitLocation); if ((DamageType == 'Flamed') || (DamageType == 'Burned')) { bBurnedToDeath = true; ScaleGlow *= 0.1; // blacken the corpse } else bBurnedToDeath = false; return; } // play a hit sound if (DamageType != 'Stunned') PlayTakeHitSound(actualDamage, damageType, 1); if ((DamageType == 'Flamed') && !bOnFire) CatchFire(); ReactToInjury(instigatedBy, damageType, hitPos); } // ---------------------------------------------------------------------- // IsNearHome() // ---------------------------------------------------------------------- function bool IsNearHome(vector position) { local bool bNear; bNear = true; if (bUseHome) { if (VSize(HomeLoc-position) <= HomeExtent) { if (!FastTrace(position, HomeLoc)) bNear = false; } else bNear = false; } return bNear; } // ---------------------------------------------------------------------- // IsDoor() // ---------------------------------------------------------------------- function bool IsDoor(Actor door, optional bool bWarn) { local bool bIsDoor; local DeusExMover dxMover; bIsDoor = false; dxMover = DeusExMover(door); if (dxMover != None) { if (dxMover.NumKeys > 1) { if (dxMover.bIsDoor) bIsDoor = true; /* else if (bWarn) // hack for now log("WARNING: NPC "$self$" trying to use door "$dxMover$", but bIsDoor flag is False"); */ } } return bIsDoor; } // ---------------------------------------------------------------------- // CheckOpenDoor() // ---------------------------------------------------------------------- function CheckOpenDoor(vector HitNormal, actor Door, optional name Label) { local DeusExMover dxMover; dxMover = DeusExMover(Door); if (dxMover != None) { if (bCanOpenDoors && !IsDoor(dxMover) && dxMover.bBreakable) // break glass we walk into { dxMover.TakeDamage(200, self, dxMover.Location, Velocity, 'Shot'); return; } if (dxMover.bInterpolating && (dxMover.MoverEncroachType == ME_IgnoreWhenEncroach)) return; if (bCanOpenDoors && bInterruptState && !bInTransientState && IsDoor(dxMover, true)) { if (Label == '') Label = 'Begin'; if (GetStateName() != 'OpeningDoor') SetNextState(GetStateName(), 'ContinueFromDoor'); Target = Door; destLoc = HitNormal; GotoState('OpeningDoor', 'BeginHitNormal'); } else if ((Acceleration != vect(0,0,0)) && (Physics == PHYS_Walking) && (TurnDirection == TURNING_None)) Destination = Location; } } // ---------------------------------------------------------------------- // EncroachedBy() // ---------------------------------------------------------------------- event EncroachedBy( actor Other ) { // overridden so indestructable NPCs aren't InstaGibbed by stupid movement code } // ---------------------------------------------------------------------- // EncroachedByMover() // ---------------------------------------------------------------------- function EncroachedByMover(Mover encroacher) { local DeusExMover dxMover; dxMover = DeusExMover(encroacher); if (dxMover != None) if (!dxMover.bInterpolating && IsDoor(dxMover)) FrobDoor(dxMover); } // ---------------------------------------------------------------------- // FrobDoor() // ---------------------------------------------------------------------- function bool FrobDoor(actor Target) { local DeusExMover dxMover; local DeusExMover triggerMover; local DeusExDecoration trigger; local float dist; local DeusExDecoration bestTrigger; local float bestDist; local bool bDone; bDone = false; dxMover = DeusExMover(Target); if (dxMover != None) { bestTrigger = None; bestDist = 10000; foreach AllActors(Class'DeusExDecoration', trigger) { if (dxMover.Tag == trigger.Event) { dist = VSize(Location - trigger.Location); if ((bestTrigger == None) || (bestDist > dist)) { bestTrigger = trigger; bestDist = dist; } } } if (bestTrigger != None) { foreach AllActors(Class'DeusExMover', triggerMover, dxMover.Tag) triggerMover.Trigger(bestTrigger, self); bDone = true; } else if (dxMover.bFrobbable) { if ((dxMover.WaitingPawn == None) || (dxMover.WaitingPawn == self)) { dxMover.Frob(self, None); bDone = true; } } if (bDone) dxMover.WaitingPawn = self; } return bDone; } // ---------------------------------------------------------------------- // GotoDisabledState() // ---------------------------------------------------------------------- function GotoDisabledState(name damageType, EHitLocation hitPos) { if (!bCollideActors && !bBlockActors && !bBlockPlayers) return; else if ((damageType == 'TearGas') || (damageType == 'HalonGas')) GotoState('RubbingEyes'); else if (damageType == 'Stunned') GotoState('Stunned'); else if (CanShowPain()) TakeHit(hitPos); else GotoNextState(); } // ---------------------------------------------------------------------- // PlayAnimPivot() // ---------------------------------------------------------------------- function PlayAnimPivot(name Sequence, optional float Rate, optional float TweenTime, optional vector NewPrePivot) { if (Rate == 0) Rate = 1.0; if (TweenTime == 0) TweenTime = 0.1; PlayAnim(Sequence, Rate, TweenTime); PrePivotTime = TweenTime; DesiredPrePivot = NewPrePivot + PrePivotOffset; if (PrePivotTime <= 0) PrePivot = DesiredPrePivot; } // ---------------------------------------------------------------------- // LoopAnimPivot() // ---------------------------------------------------------------------- function LoopAnimPivot(name Sequence, optional float Rate, optional float TweenTime, optional float MinRate, optional vector NewPrePivot) { if (Rate == 0) Rate = 1.0; if (TweenTime == 0) TweenTime = 0.1; LoopAnim(Sequence, Rate, TweenTime, MinRate); PrePivotTime = TweenTime; DesiredPrePivot = NewPrePivot + PrePivotOffset; if (PrePivotTime <= 0) PrePivot = DesiredPrePivot; } // ---------------------------------------------------------------------- // TweenAnimPivot() // ---------------------------------------------------------------------- function TweenAnimPivot(name Sequence, float TweenTime, optional vector NewPrePivot) { if (TweenTime == 0) TweenTime = 0.1; TweenAnim(Sequence, TweenTime); PrePivotTime = TweenTime; DesiredPrePivot = NewPrePivot + PrePivotOffset; if (PrePivotTime <= 0) PrePivot = DesiredPrePivot; } // ---------------------------------------------------------------------- // HasTwoHandedWeapon() // ---------------------------------------------------------------------- function Bool HasTwoHandedWeapon() { if ((Weapon != None) && (Weapon.Mass >= 30)) return True; else return False; } // ---------------------------------------------------------------------- // GetStyleTexture() // ---------------------------------------------------------------------- function Texture GetStyleTexture(ERenderStyle newStyle, texture oldTex, optional texture newTex) { local texture defaultTex; if (newStyle == STY_Translucent) defaultTex = Texture'BlackMaskTex'; else if (newStyle == STY_Modulated) defaultTex = Texture'GrayMaskTex'; else if (newStyle == STY_Masked) defaultTex = Texture'PinkMaskTex'; else defaultTex = Texture'BlackMaskTex'; if (oldTex == None) return defaultTex; else if (oldTex == Texture'BlackMaskTex') return Texture'BlackMaskTex'; // hack else if (oldTex == Texture'GrayMaskTex') return defaultTex; else if (oldTex == Texture'PinkMaskTex') return defaultTex; else if (newTex != None) return newTex; else return oldTex; } // ---------------------------------------------------------------------- // SetSkinStyle() // ---------------------------------------------------------------------- function SetSkinStyle(ERenderStyle newStyle, optional texture newTex, optional float newScaleGlow) { local int i; local texture curSkin; local texture oldSkin; if (newScaleGlow == 0) newScaleGlow = ScaleGlow; oldSkin = Skin; for (i=0; i<8; i++) { curSkin = GetMeshTexture(i); MultiSkins[i] = GetStyleTexture(newStyle, curSkin, newTex); } Skin = GetStyleTexture(newStyle, Skin, newTex); ScaleGlow = newScaleGlow; Style = newStyle; } // ---------------------------------------------------------------------- // ResetSkinStyle() // ---------------------------------------------------------------------- function ResetSkinStyle() { local int i; for (i=0; i<8; i++) MultiSkins[i] = Default.MultiSkins[i]; Skin = Default.Skin; ScaleGlow = Default.ScaleGlow; Style = Default.Style; } // ---------------------------------------------------------------------- // EnableCloak() // ---------------------------------------------------------------------- function EnableCloak(bool bEnable) // beware! called from C++ { if (!bHasCloak || (CloakEMPTimer > 0) || (Health <= 0) || bOnFire) bEnable = false; if (bEnable && !bCloakOn) { SetSkinStyle(STY_Translucent, Texture'WhiteStatic', 0.05); KillShadow(); bCloakOn = bEnable; } else if (!bEnable && bCloakOn) { ResetSkinStyle(); CreateShadow(); bCloakOn = bEnable; } } // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // SOUND FUNCTIONS // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // PlayBodyThud() // ---------------------------------------------------------------------- function PlayBodyThud() { PlaySound(sound'BodyThud', SLOT_Interact); } // ---------------------------------------------------------------------- // RandomPitch() // // Repetitive sound pitch randomizer to help make some sounds // sound less monotonous // ---------------------------------------------------------------------- function float RandomPitch() { return (1.1 - 0.2*FRand()); } // ---------------------------------------------------------------------- // Gasp() // ---------------------------------------------------------------------- function Gasp() { PlaySound(sound'MaleGasp', SLOT_Pain,,,, RandomPitch()); } // ---------------------------------------------------------------------- // PlayDyingSound() // ---------------------------------------------------------------------- function PlayDyingSound() { SetDistressTimer(); PlaySound(Die, SLOT_Pain,,,, RandomPitch()); AISendEvent('LoudNoise', EAITYPE_Audio); if (bEmitDistress) AISendEvent('Distress', EAITYPE_Audio); } // ---------------------------------------------------------------------- // PlayIdleSound() // ---------------------------------------------------------------------- function PlayIdleSound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if (dxPlayer != None) dxPlayer.StartAIBarkConversation(self, BM_Idle); } // ---------------------------------------------------------------------- // PlayScanningSound() // ---------------------------------------------------------------------- function PlayScanningSound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if (dxPlayer != None) dxPlayer.StartAIBarkConversation(self, BM_Scanning); } // ---------------------------------------------------------------------- // PlayPreAttackSearchingSound() // ---------------------------------------------------------------------- function PlayPreAttackSearchingSound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if ((dxPlayer != None) && (SeekPawn == dxPlayer)) dxPlayer.StartAIBarkConversation(self, BM_PreAttackSearching); } // ---------------------------------------------------------------------- // PlayPreAttackSightingSound() // ---------------------------------------------------------------------- function PlayPreAttackSightingSound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if ((dxPlayer != None) && (SeekPawn == dxPlayer)) dxPlayer.StartAIBarkConversation(self, BM_PreAttackSighting); } // ---------------------------------------------------------------------- // PlayPostAttackSearchingSound() // ---------------------------------------------------------------------- function PlayPostAttackSearchingSound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if ((dxPlayer != None) && (SeekPawn == dxPlayer)) dxPlayer.StartAIBarkConversation(self, BM_PostAttackSearching); } // ---------------------------------------------------------------------- // PlayTargetAcquiredSound() // ---------------------------------------------------------------------- function PlayTargetAcquiredSound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if ((dxPlayer != None) && (Enemy == dxPlayer)) dxPlayer.StartAIBarkConversation(self, BM_TargetAcquired); } // ---------------------------------------------------------------------- // PlayTargetLostSound() // ---------------------------------------------------------------------- function PlayTargetLostSound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if ((dxPlayer != None) && (SeekPawn == dxPlayer)) dxPlayer.StartAIBarkConversation(self, BM_TargetLost); } // ---------------------------------------------------------------------- // PlaySearchGiveUpSound() // ---------------------------------------------------------------------- function PlaySearchGiveUpSound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if ((dxPlayer != None) && (SeekPawn == dxPlayer)) dxPlayer.StartAIBarkConversation(self, BM_SearchGiveUp); } // ---------------------------------------------------------------------- // PlayNewTargetSound() // ---------------------------------------------------------------------- function PlayNewTargetSound() { // someday... } // ---------------------------------------------------------------------- // PlayGoingForAlarmSound() // ---------------------------------------------------------------------- function PlayGoingForAlarmSound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if ((dxPlayer != None) && (Enemy == dxPlayer)) dxPlayer.StartAIBarkConversation(self, BM_GoingForAlarm); } // ---------------------------------------------------------------------- // PlayOutOfAmmoSound() // ---------------------------------------------------------------------- function PlayOutOfAmmoSound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if (dxPlayer != None) dxPlayer.StartAIBarkConversation(self, BM_OutOfAmmo); } // ---------------------------------------------------------------------- // PlayCriticalDamageSound() // ---------------------------------------------------------------------- function PlayCriticalDamageSound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if ((dxPlayer != None) && (Enemy == dxPlayer)) dxPlayer.StartAIBarkConversation(self, BM_CriticalDamage); } // ---------------------------------------------------------------------- // PlayAreaSecureSound() // ---------------------------------------------------------------------- function PlayAreaSecureSound() { local DeusExPlayer dxPlayer; // Should we do a player check here? dxPlayer = DeusExPlayer(GetPlayerPawn()); if ((dxPlayer != None) && (Enemy == dxPlayer)) dxPlayer.StartAIBarkConversation(self, BM_AreaSecure); } // ---------------------------------------------------------------------- // PlayFutzSound() // ---------------------------------------------------------------------- function PlayFutzSound() { local DeusExPlayer dxPlayer; local Name conName; dxPlayer = DeusExPlayer(GetPlayerPawn()); if (dxPlayer != None) { if (dxPlayer.barkManager != None) { conName = dxPlayer.barkManager.BuildBarkName(self, BM_Futz); dxPlayer.StartConversationByName(conName, self, !bInterruptState); } // dxPlayer.StartAIBarkConversation(self, BM_Futz); } } // ---------------------------------------------------------------------- // PlayOnFireSound() // ---------------------------------------------------------------------- function PlayOnFireSound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if (dxPlayer != None) dxPlayer.StartAIBarkConversation(self, BM_OnFire); } // ---------------------------------------------------------------------- // PlayTearGasSound() // ---------------------------------------------------------------------- function PlayTearGasSound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if (dxPlayer != None) dxPlayer.StartAIBarkConversation(self, BM_TearGas); } // ---------------------------------------------------------------------- // PlayCarcassSound() // ---------------------------------------------------------------------- function PlayCarcassSound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if ((dxPlayer != None) && (SeekPawn == dxPlayer)) dxPlayer.StartAIBarkConversation(self, BM_Gore); } // ---------------------------------------------------------------------- // PlaySurpriseSound() // ---------------------------------------------------------------------- function PlaySurpriseSound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if ((dxPlayer != None) && (Enemy == dxPlayer)) dxPlayer.StartAIBarkConversation(self, BM_Surprise); } // ---------------------------------------------------------------------- // PlayAllianceHostileSound() // ---------------------------------------------------------------------- function PlayAllianceHostileSound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if ((dxPlayer != None) && (Enemy == dxPlayer)) dxPlayer.StartAIBarkConversation(self, BM_AllianceHostile); } // ---------------------------------------------------------------------- // PlayAllianceFriendlySound() // ---------------------------------------------------------------------- function PlayAllianceFriendlySound() { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if ((dxPlayer != None) && (Enemy == dxPlayer)) dxPlayer.StartAIBarkConversation(self, BM_AllianceFriendly); } // ---------------------------------------------------------------------- // PlayTakeHitSound() // ---------------------------------------------------------------------- function PlayTakeHitSound(int Damage, name damageType, int Mult) { local Sound hitSound; local float volume; if (Level.TimeSeconds - LastPainSound < 0.25) return; if (Damage <= 0) return; LastPainSound = Level.TimeSeconds; if (Damage <= 30) hitSound = HitSound1; else hitSound = HitSound2; volume = FMax(Mult*TransientSoundVolume, Mult*2.0); SetDistressTimer(); PlaySound(hitSound, SLOT_Pain, volume,,, RandomPitch()); if ((hitSound != None) && bEmitDistress) AISendEvent('Distress', EAITYPE_Audio, volume); } // ---------------------------------------------------------------------- // GetFloorMaterial() // // Gets the name of the texture group that we are standing on // ---------------------------------------------------------------------- function name GetFloorMaterial() { local vector EndTrace, HitLocation, HitNormal; local actor target; local int texFlags; local name texName, texGroup; // trace down to our feet EndTrace = Location - CollisionHeight * 2 * vect(0,0,1); foreach TraceTexture(class'Actor', target, texName, texGroup, texFlags, HitLocation, HitNormal, EndTrace) { if ((target == Level) || target.IsA('Mover')) break; } return texGroup; } // ---------------------------------------------------------------------- // PlayFootStep() // // Plays footstep sounds based on the texture group // (yes, I know this looks nasty -- I'll have to figure out a cleaner way to do this) // ---------------------------------------------------------------------- function PlayFootStep() { local Sound stepSound; local float rnd; local name mat; local float speedFactor, massFactor; local float volume, pitch, range; local float radius, maxRadius; local float volumeMultiplier; local DeusExPlayer dxPlayer; local float shakeRadius, shakeMagnitude; local float playerDist; rnd = FRand(); mat = GetFloorMaterial(); volumeMultiplier = 1.0; if (WalkSound == None) { if (FootRegion.Zone.bWaterZone) { if (rnd < 0.33) stepSound = Sound'WaterStep1'; else if (rnd < 0.66) stepSound = Sound'WaterStep2'; else stepSound = Sound'WaterStep3'; } else { switch(mat) { case 'Textile': case 'Paper': volumeMultiplier = 0.7; if (rnd < 0.25) stepSound = Sound'CarpetStep1'; else if (rnd < 0.5) stepSound = Sound'CarpetStep2'; else if (rnd < 0.75) stepSound = Sound'CarpetStep3'; else stepSound = Sound'CarpetStep4'; break; case 'Foliage': case 'Earth': volumeMultiplier = 0.6; if (rnd < 0.25) stepSound = Sound'GrassStep1'; else if (rnd < 0.5) stepSound = Sound'GrassStep2'; else if (rnd < 0.75) stepSound = Sound'GrassStep3'; else stepSound = Sound'GrassStep4'; break; case 'Metal': case 'Ladder': volumeMultiplier = 1.0; if (rnd < 0.25) stepSound = Sound'MetalStep1'; else if (rnd < 0.5) stepSound = Sound'MetalStep2'; else if (rnd < 0.75) stepSound = Sound'MetalStep3'; else stepSound = Sound'MetalStep4'; break; case 'Ceramic': case 'Glass': case 'Tiles': volumeMultiplier = 0.7; if (rnd < 0.25) stepSound = Sound'TileStep1'; else if (rnd < 0.5) stepSound = Sound'TileStep2'; else if (rnd < 0.75) stepSound = Sound'TileStep3'; else stepSound = Sound'TileStep4'; break; case 'Wood': volumeMultiplier = 0.7; if (rnd < 0.25) stepSound = Sound'WoodStep1'; else if (rnd < 0.5) stepSound = Sound'WoodStep2'; else if (rnd < 0.75) stepSound = Sound'WoodStep3'; else stepSound = Sound'WoodStep4'; break; case 'Brick': case 'Concrete': case 'Stone': case 'Stucco': default: volumeMultiplier = 0.7; if (rnd < 0.25) stepSound = Sound'StoneStep1'; else if (rnd < 0.5) stepSound = Sound'StoneStep2'; else if (rnd < 0.75) stepSound = Sound'StoneStep3'; else stepSound = Sound'StoneStep4'; break; } } } else stepSound = WalkSound; // compute sound volume, range and pitch, based on mass and speed speedFactor = VSize(Velocity)/120.0; massFactor = Mass/150.0; radius = 768.0; maxRadius = 2048.0; // volume = (speedFactor+0.2)*massFactor; // volume = (speedFactor+0.7)*massFactor; volume = massFactor*1.5; range = radius * volume; pitch = (volume+0.5); volume = 1.0; range = FClamp(range, 0.01, maxRadius); pitch = FClamp(pitch, 1.0, 1.5); // play the sound and send an AI event PlaySound(stepSound, SLOT_Interact, volume, , range, pitch); AISendEvent('LoudNoise', EAITYPE_Audio, volume*volumeMultiplier, range*volumeMultiplier); // Shake the camera when heavy things tread if (Mass > 400) { dxPlayer = DeusExPlayer(GetPlayerPawn()); if (dxPlayer != None) { playerDist = DistanceFromPlayer; shakeRadius = FClamp((Mass-400)/600, 0, 1.0) * (range*0.5); shakeMagnitude = FClamp((Mass-400)/1600, 0, 1.0); shakeMagnitude = FClamp(1.0-(playerDist/shakeRadius), 0, 1.0) * shakeMagnitude; if (shakeMagnitude > 0) dxPlayer.JoltView(shakeMagnitude); } } } // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // ANIMATION CALLS // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // GetSwimPivot() // ---------------------------------------------------------------------- function vector GetSwimPivot() { // THIS IS A HIDEOUS, UGLY, MASSIVELY EVIL HACK!!!! return (vect(0,0,1)*CollisionHeight*0.65); } // ---------------------------------------------------------------------- // GetWalkingSpeed() // ---------------------------------------------------------------------- function float GetWalkingSpeed() { if (Physics == PHYS_Swimming) return MaxDesiredSpeed; else return WalkingSpeed; } // ---------------------------------------------------------------------- // PlayTurnHead() // ---------------------------------------------------------------------- function bool PlayTurnHead(ELookDirection newLookDir, float rate, float tweentime) { if (bCanTurnHead) { if (Super.PlayTurnHead(newLookDir, rate, tweentime)) { AIAddViewRotation = rot(0,0,0); // default switch (newLookDir) { case LOOK_Left: AIAddViewRotation = rot(0,-5461,0); // 30 degrees left break; case LOOK_Right: AIAddViewRotation = rot(0,5461,0); // 30 degrees right break; case LOOK_Up: AIAddViewRotation = rot(5461,0,0); // 30 degrees up break; case LOOK_Down: AIAddViewRotation = rot(-5461,0,0); // 30 degrees down break; case LOOK_Forward: AIAddViewRotation = rot(0,0,0); // 0 degrees break; } } else return false; } else return false; } // ---------------------------------------------------------------------- // PlayRunningAndFiring() // ---------------------------------------------------------------------- function PlayRunningAndFiring() { local DeusExWeapon W; local vector v1, v2; local float dotp; bIsWalking = FALSE; W = DeusExWeapon(Weapon); if (W != None) { if (Region.Zone.bWaterZone) { if (W.bHandToHand) LoopAnimPivot('Tread',,0.1,,GetSwimPivot()); else LoopAnimPivot('TreadShoot',,0.1,,GetSwimPivot()); } else { if (W.bHandToHand) LoopAnimPivot('Run',runAnimMult,0.1); else { v1 = Normal((Enemy.Location - Location)*vect(1,1,0)); if (destPoint != None) v2 = Normal((destPoint.Location - Location)*vect(1,1,0)); else v2 = Normal((destLoc - Location)*vect(1,1,0)); dotp = Abs(v1 dot v2); if (dotp < 0.70710678) // running sideways { if (HasTwoHandedWeapon()) LoopAnimPivot('Strafe2H',runAnimMult,0.1); else LoopAnimPivot('Strafe',runAnimMult,0.1); } else { if (HasTwoHandedWeapon()) LoopAnimPivot('RunShoot2H',runAnimMult,0.1); else LoopAnimPivot('RunShoot',runAnimMult,0.1); } } } } } // ---------------------------------------------------------------------- // PlayReloadBegin() // ---------------------------------------------------------------------- function PlayReloadBegin() { PlayAnimPivot('ReloadBegin',, 0.1); } // ---------------------------------------------------------------------- // PlayReload() // ---------------------------------------------------------------------- function PlayReload() { LoopAnimPivot('Reload',,0.2); } // ---------------------------------------------------------------------- // PlayReloadEnd() // ---------------------------------------------------------------------- function PlayReloadEnd() { PlayAnimPivot('ReloadEnd',, 0.1); } // ---------------------------------------------------------------------- // TweenToShoot() // ---------------------------------------------------------------------- function TweenToShoot(float tweentime) { if (Region.Zone.bWaterZone) TweenAnimPivot('TreadShoot', tweentime, GetSwimPivot()); else if (!bCrouching) { if (!IsWeaponReloading()) { if (HasTwoHandedWeapon()) TweenAnimPivot('Shoot2H', tweentime); else TweenAnimPivot('Shoot', tweentime); } else PlayReload(); } } // ---------------------------------------------------------------------- // PlayShoot() // ---------------------------------------------------------------------- function PlayShoot() { if (Region.Zone.bWaterZone) PlayAnimPivot('TreadShoot', , 0, GetSwimPivot()); else { if (HasTwoHandedWeapon()) PlayAnimPivot('Shoot2H', , 0); else PlayAnimPivot('Shoot', , 0); } } // ---------------------------------------------------------------------- // TweenToCrouchShoot() // ---------------------------------------------------------------------- function TweenToCrouchShoot(float tweentime) { if (Region.Zone.bWaterZone) TweenAnimPivot('TreadShoot', tweentime, GetSwimPivot()); else TweenAnimPivot('CrouchShoot', tweentime); } // ---------------------------------------------------------------------- // PlayCrouchShoot() // ---------------------------------------------------------------------- function PlayCrouchShoot() { if (Region.Zone.bWaterZone) PlayAnimPivot('TreadShoot', , 0, GetSwimPivot()); else PlayAnimPivot('CrouchShoot', , 0); } // ---------------------------------------------------------------------- // TweenToAttack() // ---------------------------------------------------------------------- function TweenToAttack(float tweentime) { if (Region.Zone.bWaterZone) TweenAnimPivot('Tread', tweentime, GetSwimPivot()); else { if (bUseSecondaryAttack) TweenAnimPivot('AttackSide', tweentime); else TweenAnimPivot('Attack', tweentime); } } // ---------------------------------------------------------------------- // PlayAttack() // ---------------------------------------------------------------------- function PlayAttack() { if (Region.Zone.bWaterZone) PlayAnimPivot('Tread',,,GetSwimPivot()); else { if (bUseSecondaryAttack) PlayAnimPivot('AttackSide'); else PlayAnimPivot('Attack'); } } // ---------------------------------------------------------------------- // PlayTurning() // ---------------------------------------------------------------------- function PlayTurning() { // ClientMessage("PlayTurning()"); if (Region.Zone.bWaterZone) LoopAnimPivot('Tread', , , , GetSwimPivot()); else { if (HasTwoHandedWeapon()) TweenAnimPivot('Walk2H', 0.1); else TweenAnimPivot('Walk', 0.1); } } // ---------------------------------------------------------------------- // TweenToWalking() // ---------------------------------------------------------------------- function TweenToWalking(float tweentime) { // ClientMessage("TweenToWalking()"); bIsWalking = True; if (Region.Zone.bWaterZone) TweenAnimPivot('Tread', tweentime, GetSwimPivot()); else { if (HasTwoHandedWeapon()) TweenAnimPivot('Walk2H', tweentime); else TweenAnimPivot('Walk', tweentime); } } // ---------------------------------------------------------------------- // PlayWalking() // ---------------------------------------------------------------------- function PlayWalking() { // ClientMessage("PlayWalking()"); bIsWalking = True; if (Region.Zone.bWaterZone) LoopAnimPivot('Tread', , 0.15, , GetSwimPivot()); else { if (HasTwoHandedWeapon()) LoopAnimPivot('Walk2H',walkAnimMult, 0.15); else LoopAnimPivot('Walk',walkAnimMult, 0.15); } } // ---------------------------------------------------------------------- // TweenToRunning() // ---------------------------------------------------------------------- function TweenToRunning(float tweentime) { // ClientMessage("TweenToRunning()"); bIsWalking = False; if (Region.Zone.bWaterZone) LoopAnimPivot('Tread',, tweentime,, GetSwimPivot()); else { if (HasTwoHandedWeapon()) LoopAnimPivot('RunShoot2H', runAnimMult, tweentime); else LoopAnimPivot('Run', runAnimMult, tweentime); } } // ---------------------------------------------------------------------- // PlayRunning() // ---------------------------------------------------------------------- function PlayRunning() { // ClientMessage("PlayRunning()"); bIsWalking = False; if (Region.Zone.bWaterZone) LoopAnimPivot('Tread',,,,GetSwimPivot()); else { if (HasTwoHandedWeapon()) LoopAnimPivot('RunShoot2H', runAnimMult); else LoopAnimPivot('Run', runAnimMult); } } // ---------------------------------------------------------------------- // PlayPanicRunning() // ---------------------------------------------------------------------- function PlayPanicRunning() { // ClientMessage("PlayPanicRunning()"); bIsWalking = False; if (Region.Zone.bWaterZone) LoopAnimPivot('Tread',,,,GetSwimPivot()); else LoopAnimPivot('Panic', runAnimMult); } // ---------------------------------------------------------------------- // TweenToWaiting() // ---------------------------------------------------------------------- function TweenToWaiting(float tweentime) { // ClientMessage("TweenToWaiting()"); if (Region.Zone.bWaterZone) TweenAnimPivot('Tread', tweentime, GetSwimPivot()); else { if (HasTwoHandedWeapon()) TweenAnimPivot('BreatheLight2H', tweentime); else TweenAnimPivot('BreatheLight', tweentime); } } // ---------------------------------------------------------------------- // PlayWaiting() // ---------------------------------------------------------------------- function PlayWaiting() { // ClientMessage("PlayWaiting()"); if (Region.Zone.bWaterZone) LoopAnimPivot('Tread', , 0.3, , GetSwimPivot()); else { if (HasTwoHandedWeapon()) LoopAnimPivot('BreatheLight2H', , 0.3); else LoopAnimPivot('BreatheLight', , 0.3); } } // ---------------------------------------------------------------------- // PlayIdle() // ---------------------------------------------------------------------- function PlayIdle() { // ClientMessage("PlayIdle()"); if (Region.Zone.bWaterZone) LoopAnimPivot('Tread', , 0.3, , GetSwimPivot()); else { if (HasTwoHandedWeapon()) PlayAnimPivot('Idle12H', , 0.3); else PlayAnimPivot('Idle1', , 0.3); } } // ---------------------------------------------------------------------- // PlayDancing() // ---------------------------------------------------------------------- function PlayDancing() { // ClientMessage("PlayDancing()"); if (Region.Zone.bWaterZone) LoopAnimPivot('Tread', , 0.3, , GetSwimPivot()); else LoopAnimPivot('Dance', FRand()*0.2+0.9, 0.3); } // ---------------------------------------------------------------------- // PlaySittingDown() // ---------------------------------------------------------------------- function PlaySittingDown() { // ClientMessage("PlaySittingDown()"); PlayAnimPivot('SitBegin', , 0.15); } // ---------------------------------------------------------------------- // PlaySitting() // ---------------------------------------------------------------------- function PlaySitting() { // ClientMessage("PlaySitting()"); LoopAnimPivot('SitBreathe', , 0.15); } // ---------------------------------------------------------------------- // PlayStandingUp() // ---------------------------------------------------------------------- function PlayStandingUp() { // ClientMessage("PlayStandingUp()"); PlayAnimPivot('SitStand', , 0.15); } // ---------------------------------------------------------------------- // PlayRubbingEyesStart() // ---------------------------------------------------------------------- function PlayRubbingEyesStart() { // ClientMessage("PlayRubbingEyesStart()"); PlayAnimPivot('RubEyesStart', , 0.15); } // ---------------------------------------------------------------------- // PlayRubbingEyes() // ---------------------------------------------------------------------- function PlayRubbingEyes() { // ClientMessage("PlayRubbingEyes()"); LoopAnimPivot('RubEyes'); } // ---------------------------------------------------------------------- // PlayRubbingEyesEnd() // ---------------------------------------------------------------------- function PlayRubbingEyesEnd() { // ClientMessage("PlayRubbingEyesEnd()"); PlayAnimPivot('RubEyesStop'); } // ---------------------------------------------------------------------- // PlayCowerBegin() // ---------------------------------------------------------------------- function PlayCowerBegin() { // ClientMessage("PlayCowerBegin()"); if (Region.Zone.bWaterZone) LoopAnimPivot('Tread',,,,GetSwimPivot()); else PlayAnimPivot('CowerBegin'); } // ---------------------------------------------------------------------- // PlayCowering() // ---------------------------------------------------------------------- function PlayCowering() { // ClientMessage("PlayCowering()"); if (Region.Zone.bWaterZone) LoopAnimPivot('Tread',,,,GetSwimPivot()); else LoopAnimPivot('CowerStill'); } // ---------------------------------------------------------------------- // PlayCowerEnd() // ---------------------------------------------------------------------- function PlayCowerEnd() { // ClientMessage("PlayCowerEnd()"); if (Region.Zone.bWaterZone) LoopAnimPivot('Tread',,,,GetSwimPivot()); else PlayAnimPivot('CowerEnd'); } // ---------------------------------------------------------------------- // PlayStunned() // ---------------------------------------------------------------------- function PlayStunned() { // ClientMessage("PlayStunned()"); LoopAnimPivot('Shocked'); } // ---------------------------------------------------------------------- // TweenToSwimming() // ---------------------------------------------------------------------- function TweenToSwimming(float tweentime) { // ClientMessage("TweenToSwimming()"); TweenAnimPivot('Tread', tweentime, GetSwimPivot()); } // ---------------------------------------------------------------------- // PlaySwimming() // ---------------------------------------------------------------------- function PlaySwimming() { // ClientMessage("PlaySwimming()"); LoopAnimPivot('Tread', , , , GetSwimPivot()); } // ---------------------------------------------------------------------- // PlayFalling() // ---------------------------------------------------------------------- function PlayFalling() { // ClientMessage("PlayFalling()"); PlayAnimPivot('Jump', 3, 0.1); } // ---------------------------------------------------------------------- // PlayLanded() // ---------------------------------------------------------------------- function PlayLanded(float impactVel) { // ClientMessage("PlayLanded()"); bIsWalking = True; if (impactVel < -12*CollisionHeight) PlayAnimPivot('Land'); } // ---------------------------------------------------------------------- // PlayDuck() // ---------------------------------------------------------------------- function PlayDuck() { // ClientMessage("PlayDuck()"); TweenAnimPivot('CrouchWalk', 0.25); // PlayAnimPivot('Crouch'); } // ---------------------------------------------------------------------- // PlayRising() // ---------------------------------------------------------------------- function PlayRising() { // ClientMessage("PlayRising()"); PlayAnimPivot('Stand'); } // ---------------------------------------------------------------------- // PlayCrawling() // ---------------------------------------------------------------------- function PlayCrawling() { // ClientMessage("PlayCrawling()"); LoopAnimPivot('CrouchWalk'); } // ---------------------------------------------------------------------- // PlayPushing() // ---------------------------------------------------------------------- function PlayPushing() { // ClientMessage("PlayPushing()"); PlayAnimPivot('PushButton', , 0.15); } // ---------------------------------------------------------------------- // PlayBeginAttack() // ---------------------------------------------------------------------- function bool PlayBeginAttack() { return false; } // ---------------------------------------------------------------------- // PlayFiring() // ---------------------------------------------------------------------- /* function PlayFiring() { local DeusExWeapon W; // ClientMessage("PlayFiring()"); W = DeusExWeapon(Weapon); if (W != None) { if (W.bHandToHand) { PlayAnimPivot('Attack',,0.1); } else { if (W.bAutomatic) { if (HasTwoHandedWeapon()) LoopAnimPivot('Shoot2H',,0.1); else LoopAnimPivot('Shoot',,0.1); } else { if (HasTwoHandedWeapon()) PlayAnimPivot('Shoot2H',,0.1); else PlayAnimPivot('Shoot',,0.1); } } } } */ // ---------------------------------------------------------------------- // PlayTakingHit() // ---------------------------------------------------------------------- function PlayTakingHit(EHitLocation hitPos) { local vector pivot; local name animName; animName = ''; if (!Region.Zone.bWaterZone) { switch (hitPos) { case HITLOC_HeadFront: animName = 'HitHead'; break; case HITLOC_TorsoFront: animName = 'HitTorso'; break; case HITLOC_LeftArmFront: animName = 'HitArmLeft'; break; case HITLOC_RightArmFront: animName = 'HitArmRight'; break; case HITLOC_HeadBack: animName = 'HitHeadBack'; break; case HITLOC_TorsoBack: case HITLOC_LeftArmBack: case HITLOC_RightArmBack: animName = 'HitTorsoBack'; break; case HITLOC_LeftLegFront: case HITLOC_LeftLegBack: animName = 'HitLegLeft'; break; case HITLOC_RightLegFront: case HITLOC_RightLegBack: animName = 'HitLegRight'; break; } pivot = vect(0,0,0); } else { switch (hitPos) { case HITLOC_HeadFront: case HITLOC_TorsoFront: case HITLOC_LeftLegFront: case HITLOC_RightLegFront: case HITLOC_LeftArmFront: case HITLOC_RightArmFront: animName = 'WaterHitTorso'; break; case HITLOC_HeadBack: case HITLOC_TorsoBack: case HITLOC_LeftLegBack: case HITLOC_RightLegBack: case HITLOC_LeftArmBack: case HITLOC_RightArmBack: animName = 'WaterHitTorsoBack'; break; } pivot = GetSwimPivot(); } if (animName != '') PlayAnimPivot(animName, , 0.1, pivot); } // ---------------------------------------------------------------------- // PlayWeaponSwitch() // ---------------------------------------------------------------------- function PlayWeaponSwitch(Weapon newWeapon) { // ClientMessage("PlayWeaponSwitch()"); } // ---------------------------------------------------------------------- // PlayDying() // ---------------------------------------------------------------------- function PlayDying(name damageType, vector hitLoc) { local Vector X, Y, Z; local float dotp; // ClientMessage("PlayDying()"); if (Region.Zone.bWaterZone) PlayAnimPivot('WaterDeath',, 0.1); else if (bSitting) // if sitting, always fall forward PlayAnimPivot('DeathFront',, 0.1); else { GetAxes(Rotation, X, Y, Z); dotp = (Location - HitLoc) dot X; // die from the correct side if (dotp < 0.0) // shot from the front, fall back PlayAnimPivot('DeathBack',, 0.1); else // shot from the back, fall front PlayAnimPivot('DeathFront',, 0.1); } // don't scream if we are stunned if ((damageType == 'Stunned') || (damageType == 'KnockedOut') || (damageType == 'Poison') || (damageType == 'PoisonEffect')) { bStunned = True; if (bIsFemale) PlaySound(Sound'FemaleUnconscious', SLOT_Pain,,,, RandomPitch()); else PlaySound(Sound'MaleUnconscious', SLOT_Pain,,,, RandomPitch()); } else { bStunned = False; PlayDyingSound(); } } // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // FIRE ROUTINES // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // CatchFire() // ---------------------------------------------------------------------- function CatchFire() { local Fire f; local int i; local vector loc; if (bOnFire || Region.Zone.bWaterZone || (BurnPeriod <= 0) || bInvincible) return; bOnFire = True; burnTimer = 0; EnableCloak(false); for (i=0; i<8; i++) { loc.X = 0.5*CollisionRadius * (1.0-2.0*FRand()); loc.Y = 0.5*CollisionRadius * (1.0-2.0*FRand()); loc.Z = 0.6*CollisionHeight * (1.0-2.0*FRand()); loc += Location; f = Spawn(class'Fire', Self,, loc); if (f != None) { f.DrawScale = 0.5*FRand() + 1.0; // turn off the sound and lights for all but the first one if (i > 0) { f.AmbientSound = None; f.LightType = LT_None; } // turn on/off extra fire and smoke if (FRand() < 0.5) f.smokeGen.Destroy(); if (FRand() < 0.5) f.AddFire(); } } // set the burn timer SetTimer(1.0, True); } // ---------------------------------------------------------------------- // ExtinguishFire() // ---------------------------------------------------------------------- function ExtinguishFire() { local Fire f; bOnFire = False; burnTimer = 0; SetTimer(0, False); foreach BasedActors(class'Fire', f) f.Destroy(); } // ---------------------------------------------------------------------- // UpdateFire() // ---------------------------------------------------------------------- function UpdateFire() { // continually burn and do damage HealthTorso -= 5; GenerateTotalHealth(); if (Health <= 0) { TakeDamage(10, None, Location, vect(0,0,0), 'Burned'); ExtinguishFire(); } } // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // CONVERSATION FUNCTIONS // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // CanConverse() // ---------------------------------------------------------------------- function bool CanConverse() { // Return True if this NPC is in a conversable state return (bCanConverse && bInterruptState && ((Physics == PHYS_Walking) || (Physics == PHYS_Flying))); } // ---------------------------------------------------------------------- // CanConverseWithPlayer() // ---------------------------------------------------------------------- function bool CanConverseWithPlayer(DeusExPlayer dxPlayer) { local name alliance1, alliance2, carcname; // temp vars if (GetPawnAllianceType(dxPlayer) == ALLIANCE_Hostile) return false; else if ((GetStateName() == 'Fleeing') && (Enemy != dxPlayer) && (IsValidEnemy(Enemy, false))) // hack return false; else if (GetCarcassData(dxPlayer, alliance1, alliance2, carcname)) return false; else return true; } // ---------------------------------------------------------------------- // EndConversation() // ---------------------------------------------------------------------- function EndConversation() { Super.EndConversation(); if ((GetStateName() == 'Conversation') || (GetStateName() == 'FirstPersonConversation')) { bConversationEndedNormally = True; if (!bConvEndState) FollowOrders(); } bInConversation = False; } // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // STIMULI AND AGITATION ROUTINES // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // LoudNoiseScore() // ---------------------------------------------------------------------- function float LoudNoiseScore(actor receiver, actor sender, float score) { local Pawn pawnSender; // Cull events received from friends pawnSender = Pawn(sender); if (pawnSender == None) pawnSender = sender.Instigator; if (pawnSender == None) score = 0; else if (!IsValidEnemy(pawnSender)) score = 0; return score; } // ---------------------------------------------------------------------- // WeaponDrawnScore() // ---------------------------------------------------------------------- function float WeaponDrawnScore(actor receiver, actor sender, float score) { local Pawn pawnSender; // Cull events received from enemies pawnSender = Pawn(sender); if (pawnSender == None) pawnSender = Pawn(sender.Owner); if (pawnSender == None) pawnSender = sender.Instigator; if (pawnSender == None) score = 0; else if (IsValidEnemy(pawnSender)) score = 0; return score; } // ---------------------------------------------------------------------- // DistressScore() // ---------------------------------------------------------------------- function float DistressScore(actor receiver, actor sender, float score) { local ScriptedPawn scriptedSender; local Pawn pawnSender; // Cull events received from enemies sender = InstigatorToPawn(sender); // hack pawnSender = Pawn(sender); scriptedSender = ScriptedPawn(sender); if (pawnSender == None) score = 0; else if ((GetPawnAllianceType(pawnSender) != ALLIANCE_Friendly) && !bFearDistress) score = 0; else if ((scriptedSender != None) && !scriptedSender.bDistressed) score = 0; return score; } // ---------------------------------------------------------------------- // UpdateReactionCallbacks() // ---------------------------------------------------------------------- function UpdateReactionCallbacks() { if (bReactFutz && bLookingForFutz) AISetEventCallback('Futz', 'HandleFutz', , true, true, false, true); else AIClearEventCallback('Futz'); if ((bHateHacking || bFearHacking) && bLookingForHacking) AISetEventCallback('MegaFutz', 'HandleHacking', , true, true, true, true); else AIClearEventCallback('MegaFutz'); if ((bHateWeapon || bFearWeapon) && bLookingForWeapon) AISetEventCallback('WeaponDrawn', 'HandleWeapon', 'WeaponDrawnScore', true, true, false, true); else AIClearEventCallback('WeaponDrawn'); if ((bReactShot || bFearShot || bHateShot) && bLookingForShot) AISetEventCallback('WeaponFire', 'HandleShot', , true, true, false, true); else AIClearEventCallback('WeaponFire'); /* if ((bHateCarcass || bReactCarcass || bFearCarcass) && bLookingForCarcass) AISetEventCallback('Carcass', 'HandleCarcass', 'CarcassScore', true, true, false, true); else AIClearEventCallback('Carcass'); */ if (bReactLoudNoise && bLookingForLoudNoise) AISetEventCallback('LoudNoise', 'HandleLoudNoise', 'LoudNoiseScore'); else AIClearEventCallback('LoudNoise'); if ((bReactAlarm || bFearAlarm) && bLookingForAlarm) AISetEventCallback('Alarm', 'HandleAlarm'); else AIClearEventCallback('Alarm'); if ((bHateDistress || bReactDistress || bFearDistress) && bLookingForDistress) AISetEventCallback('Distress', 'HandleDistress', 'DistressScore', true, true, false, true); else AIClearEventCallback('Distress'); if ((bFearProjectiles || bReactProjectiles) && bLookingForProjectiles) AISetEventCallback('Projectile', 'HandleProjectiles', , false, true, false, true); else AIClearEventCallback('Projectile'); } // ---------------------------------------------------------------------- // SetReactions() // ---------------------------------------------------------------------- function SetReactions(bool bEnemy, bool bLoudNoise, bool bAlarm, bool bDistress, bool bProjectile, bool bFutz, bool bHacking, bool bShot, bool bWeapon, bool bCarcass, bool bInjury, bool bIndirectInjury) { bLookingForEnemy = bEnemy; bLookingForLoudNoise = bLoudNoise; bLookingForAlarm = bAlarm; bLookingForDistress = bDistress; bLookingForProjectiles = bProjectile; bLookingForFutz = bFutz; bLookingForHacking = bHacking; bLookingForShot = bShot; bLookingForWeapon = bWeapon; bLookingForCarcass = bCarcass; bLookingForInjury = bInjury; bLookingForIndirectInjury = bIndirectInjury; UpdateReactionCallbacks(); } // ---------------------------------------------------------------------- // BlockReactions() // ---------------------------------------------------------------------- function BlockReactions(optional bool bBlockInjury) { SetReactions(false, false, false, false, false, false, false, false, false, false, !bBlockInjury, !bBlockInjury); } // ---------------------------------------------------------------------- // ResetReactions() // ---------------------------------------------------------------------- function ResetReactions() { SetReactions(true, true, true, true, true, true, true, true, true, true, true, true); } // ---------------------------------------------------------------------- // HandleFutz() // ---------------------------------------------------------------------- function HandleFutz(Name event, EAIEventState state, XAIParams params) { // React if (state == EAISTATE_Begin || state == EAISTATE_Pulse) ReactToFutz(); // only players can futz } // ---------------------------------------------------------------------- // HandleHacking() // ---------------------------------------------------------------------- function HandleHacking(Name event, EAIEventState state, XAIParams params) { // Fear, Hate local Pawn pawnActor; if (state == EAISTATE_Begin || state == EAISTATE_Pulse) { pawnActor = GetPlayerPawn(); if (pawnActor != None) { if (bHateHacking) IncreaseAgitation(pawnActor, 1.0); if (bFearHacking) IncreaseFear(pawnActor, 0.51); if (SetEnemy(pawnActor)) { SetDistressTimer(); HandleEnemy(); } else if (bFearHacking && IsFearful()) { SetDistressTimer(); SetEnemy(pawnActor, , true); GotoState('Fleeing'); } else // only players can hack ReactToFutz(); } } } // ---------------------------------------------------------------------- // HandleWeapon() // ---------------------------------------------------------------------- function HandleWeapon(Name event, EAIEventState state, XAIParams params) { // Fear, Hate local Pawn pawnActor; if (state == EAISTATE_Begin || state == EAISTATE_Pulse) { pawnActor = InstigatorToPawn(params.bestActor); if (pawnActor != None) { if (bHateWeapon) IncreaseAgitation(pawnActor); if (bFearWeapon) IncreaseFear(pawnActor, 1.0); // Let presence checking handle enemy sighting if (!IsValidEnemy(pawnActor)) { if (bFearWeapon && IsFearful()) { SetDistressTimer(); SetEnemy(pawnActor, , true); GotoState('Fleeing'); } else if (pawnActor.bIsPlayer) ReactToFutz(); } } } } // ---------------------------------------------------------------------- // HandleShot() // ---------------------------------------------------------------------- function HandleShot(Name event, EAIEventState state, XAIParams params) { // React, Fear, Hate local Pawn pawnActor; if (state == EAISTATE_Begin || state == EAISTATE_Pulse) { pawnActor = InstigatorToPawn(params.bestActor); if (pawnActor != None) { if (bHateShot) IncreaseAgitation(pawnActor); if (bFearShot) IncreaseFear(pawnActor, 1.0); if (SetEnemy(pawnActor)) { SetDistressTimer(); HandleEnemy(); } else if (bFearShot && IsFearful()) { SetDistressTimer(); SetEnemy(pawnActor, , true); GotoState('Fleeing'); } else if (pawnActor.bIsPlayer) ReactToFutz(); } } } // ---------------------------------------------------------------------- // HandleLoudNoise() // ---------------------------------------------------------------------- function HandleLoudNoise(Name event, EAIEventState state, XAIParams params) { // React local Actor bestActor; local Pawn instigator; if (state == EAISTATE_Begin || state == EAISTATE_Pulse) { bestActor = params.bestActor; if (bestActor != None) { instigator = Pawn(bestActor); if (instigator == None) instigator = bestActor.Instigator; if (instigator != None) { if (IsValidEnemy(instigator)) { SetSeekLocation(instigator, bestActor.Location, SEEKTYPE_Sound); HandleEnemy(); } } } } } // ---------------------------------------------------------------------- // HandleProjectiles() // ---------------------------------------------------------------------- function HandleProjectiles(Name event, EAIEventState state, XAIParams params) { // React, Fear local DeusExProjectile dxProjectile; if (state == EAISTATE_Begin || state == EAISTATE_Pulse) if (params.bestActor != None) ReactToProjectiles(params.bestActor); } // ---------------------------------------------------------------------- // HandleAlarm() // ---------------------------------------------------------------------- function HandleAlarm(Name event, EAIEventState state, XAIParams params) { // React, Fear local AlarmUnit alarm; local LaserTrigger laser; local SecurityCamera camera; local Computers computer; local Pawn alarmInstigator; local vector alarmLocation; if (state == EAISTATE_Begin || state == EAISTATE_Pulse) { alarmInstigator = None; alarm = AlarmUnit(params.bestActor); laser = LaserTrigger(params.bestActor); camera = SecurityCamera(params.bestActor); computer = Computers(params.bestActor); if (alarm != None) { alarmInstigator = alarm.alarmInstigator; alarmLocation = alarm.alarmLocation; } else if (laser != None) { alarmInstigator = Pawn(laser.triggerActor); if (alarmInstigator == None) alarmInstigator = laser.triggerActor.Instigator; alarmLocation = laser.actorLocation; } else if (camera != None) { alarmInstigator = GetPlayerPawn(); // player is implicit for cameras alarmLocation = camera.playerLocation; } else if (computer != None) { alarmInstigator = GetPlayerPawn(); // player is implicit for computers alarmLocation = computer.Location; } if (bFearAlarm) { IncreaseFear(alarmInstigator, 2.0); if (IsFearful()) { SetDistressTimer(); SetEnemy(alarmInstigator, , true); GotoState('Fleeing'); } } if (alarmInstigator != None) { if (alarmInstigator.Health > 0) { if (IsValidEnemy(alarmInstigator)) { AlarmTimer = 120; SetDistressTimer(); SetSeekLocation(alarmInstigator, alarmLocation, SEEKTYPE_Sound); HandleEnemy(); } } } } } // ---------------------------------------------------------------------- // HandleDistress() // ---------------------------------------------------------------------- function HandleDistress(Name event, EAIEventState state, XAIParams params) { // React, Fear, Hate local float seeTime; local Pawn distressee; local DeusExPlayer distresseePlayer; local ScriptedPawn distresseePawn; local Pawn distressor; local DeusExPlayer distressorPlayer; local ScriptedPawn distressorPawn; local bool bDistresseeValid; local bool bDistressorValid; local float distressVal; local name stateName; local bool bAttacking; local bool bFleeing; bAttacking = false; seeTime = 0; if (state == EAISTATE_Begin || state == EAISTATE_Pulse) { distressee = InstigatorToPawn(params.bestActor); if (distressee != None) { if (bFearDistress) IncreaseFear(distressee.Enemy, 1.0); bDistresseeValid = false; bDistressorValid = false; distresseePlayer = DeusExPlayer(distressee); distresseePawn = ScriptedPawn(distressee); if (GetPawnAllianceType(distressee) == ALLIANCE_Friendly) { if (distresseePawn != None) { if (distresseePawn.bDistressed && (distresseePawn.EnemyLastSeen <= EnemyTimeout)) { bDistresseeValid = true; seeTime = distresseePawn.EnemyLastSeen; } } else if (distresseePlayer != None) bDistresseeValid = true; } if (bDistresseeValid) { distressor = distressee.Enemy; distressorPlayer = DeusExPlayer(distressor); distressorPawn = ScriptedPawn(distressor); if (distressorPawn != None) { if (bHateDistress || (distressorPawn.GetPawnAllianceType(distressee) == ALLIANCE_Hostile)) bDistressorValid = true; } else if (distresseePawn != None) { if (bHateDistress || (distresseePawn.GetPawnAllianceType(distressor) == ALLIANCE_Hostile)) bDistressorValid = true; } // Finally, react if (bDistressorValid) { if (bHateDistress) IncreaseAgitation(distressor, 1.0); if (SetEnemy(distressor, seeTime)) { SetDistressTimer(); HandleEnemy(); bAttacking = true; } } // BOOGER! Make NPCs react by seeking if distressor isn't an enemy? } if (!bAttacking && bFearDistress) { distressVal = 0; bFleeing = false; if (distresseePawn != None) { stateName = distresseePawn.GetStateName(); if (stateName == 'Fleeing') // hack -- to prevent infinite fleeing { if (distresseePawn.DistressTimer >= 0) { if (FearSustainTime - distresseePawn.DistressTimer >= 1) { IncreaseFear(distressee.Enemy, 1.0, distresseePawn.DistressTimer); distressVal = distresseePawn.DistressTimer; bFleeing = true; } } } else { IncreaseFear(distressee.Enemy, 1.0); bFleeing = true; } } else { IncreaseFear(distressee.Enemy, 1.0); bFleeing = true; } if (bFleeing && IsFearful()) { if ((DistressTimer > distressVal) || (DistressTimer < 0)) DistressTimer = distressVal; SetEnemy(distressee.Enemy, , true); GotoState('Fleeing'); } } } } } // ---------------------------------------------------------------------- // IncreaseFear() // ---------------------------------------------------------------------- function IncreaseFear(Actor actorInstigator, float addedFearLevel, optional float newFearTimer) { local DeusExPlayer player; local Pawn instigator; instigator = InstigatorToPawn(actorInstigator); if (instigator != None) { if (FearTimer < (FearSustainTime-newFearTimer)) FearTimer = FearSustainTime-newFearTimer; if (FearTimer > 0) { if (addedFearLevel > 0) { FearLevel += addedFearLevel; if (FearLevel > 1.0) FearLevel = 1.0; } } } } // ---------------------------------------------------------------------- // IncreaseAgitation() // ---------------------------------------------------------------------- function IncreaseAgitation(Actor actorInstigator, optional float AgitationLevel) { local Pawn instigator; local float minLevel; instigator = InstigatorToPawn(actorInstigator); if (instigator != None) { AgitationTimer = AgitationSustainTime; if (AgitationCheckTimer <= 0) { AgitationCheckTimer = 1.5; // hardcoded for now if (AgitationLevel == 0) { if (MaxProvocations < 0) MaxProvocations = 0; AgitationLevel = 1.0/(MaxProvocations+1); } if (AgitationLevel > 0) { bAlliancesChanged = True; bNoNegativeAlliances = False; AgitateAlliance(instigator.Alliance, AgitationLevel); } } } } // ---------------------------------------------------------------------- // DecreaseAgitation() // ---------------------------------------------------------------------- function DecreaseAgitation(Actor actorInstigator, float AgitationLevel) { local float newLevel; local DeusExPlayer player; local Pawn instigator; player = DeusExPlayer(GetPlayerPawn()); if (Inventory(actorInstigator) != None) { if (Inventory(actorInstigator).Owner != None) actorInstigator = Inventory(actorInstigator).Owner; } else if (DeusExDecoration(actorInstigator) != None) actorInstigator = player; instigator = Pawn(actorInstigator); if ((instigator == None) || (instigator == self)) return; AgitationTimer = AgitationSustainTime; if (AgitationLevel > 0) { bAlliancesChanged = True; bNoNegativeAlliances = False; AgitateAlliance(instigator.Alliance, -AgitationLevel); } } // ---------------------------------------------------------------------- // UpdateAgitation() // ---------------------------------------------------------------------- function UpdateAgitation(float deltaSeconds) { local float mult; local float decrement; local int i; if (AgitationCheckTimer > 0) { AgitationCheckTimer -= deltaSeconds; if (AgitationCheckTimer < 0) AgitationCheckTimer = 0; } decrement = 0; if (AgitationTimer > 0) { if (AgitationTimer < deltaSeconds) { mult = 1.0 - (AgitationTimer/deltaSeconds); AgitationTimer = 0; decrement = mult * (AgitationDecayRate*deltaSeconds); } else AgitationTimer -= deltaSeconds; } else decrement = AgitationDecayRate*deltaSeconds; if (bAlliancesChanged && (decrement > 0)) { bAlliancesChanged = False; for (i=15; i>=0; i--) { if ((AlliancesEx[i].AllianceName != '') && (!AlliancesEx[i].bPermanent)) { if (AlliancesEx[i].AgitationLevel > 0) { bAlliancesChanged = true; AlliancesEx[i].AgitationLevel -= decrement; if (AlliancesEx[i].AgitationLevel < 0) AlliancesEx[i].AgitationLevel = 0; } } } } } // ---------------------------------------------------------------------- // UpdateFear() // ---------------------------------------------------------------------- function UpdateFear(float deltaSeconds) { local float mult; local float decrement; local int i; decrement = 0; if (FearTimer > 0) { if (FearTimer < deltaSeconds) { mult = 1.0 - (FearTimer/deltaSeconds); FearTimer = 0; decrement = mult * (FearDecayRate*deltaSeconds); } else FearTimer -= deltaSeconds; } else decrement = FearDecayRate*deltaSeconds; if ((decrement > 0) && (FearLevel > 0)) { FearLevel -= decrement; if (FearLevel < 0) FearLevel = 0; } } // ---------------------------------------------------------------------- // IsFearful() // ---------------------------------------------------------------------- function bool IsFearful() { if (FearLevel >= 1.0) return true; else return false; } // ---------------------------------------------------------------------- // ShouldBeStartled() [stub function, overridden by subclasses] // ---------------------------------------------------------------------- function bool ShouldBeStartled(Pawn startler) { return false; } // ---------------------------------------------------------------------- // ShouldPlayTurn() // ---------------------------------------------------------------------- function bool ShouldPlayTurn(vector lookdir) { local Rotator rot; rot = Rotator(lookdir); rot.Yaw = (rot.Yaw - Rotation.Yaw) & 65535; if (rot.Yaw > 32767) rot.Yaw = 65536 - rot.Yaw; // negate if (rot.Yaw > 4096) return true; else return false; } // ---------------------------------------------------------------------- // ShouldPlayWalk() // ---------------------------------------------------------------------- function bool ShouldPlayWalk(vector movedir) { local vector diff; if (Physics == PHYS_Falling) return true; else if (Physics == PHYS_Walking) { diff = (movedir - Location) * vect(1,1,0); if (VSize(diff) < 16) return false; else return true; } else if (VSize(movedir-Location) < 16) return false; else return true; } // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // ALLIANCE ROUTINES // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // SetAlliance() // ---------------------------------------------------------------------- function SetAlliance(Name newAlliance) { Alliance = newAlliance; } // ---------------------------------------------------------------------- // ChangeAlly() // ---------------------------------------------------------------------- function ChangeAlly(Name newAlly, optional float allyLevel, optional bool bPermanent, optional bool bHonorPermanence) { local int i; // Members of the same alliance will ALWAYS be friendly to each other if (newAlly == Alliance) { allyLevel = 1; bPermanent = true; } if (bHonorPermanence) { for (i=0; i<16; i++) if (AlliancesEx[i].AllianceName == newAlly) if (AlliancesEx[i].bPermanent) break; if (i < 16) return; } if (allyLevel < -1) allyLevel = -1; if (allyLevel > 1) allyLevel = 1; for (i=0; i<16; i++) if ((AlliancesEx[i].AllianceName == newAlly) || (AlliancesEx[i].AllianceName == '')) break; if (i >= 16) for (i=15; i>0; i--) AlliancesEx[i] = AlliancesEx[i-1]; AlliancesEx[i].AllianceName = newAlly; AlliancesEx[i].AllianceLevel = allyLevel; AlliancesEx[i].AgitationLevel = 0; AlliancesEx[i].bPermanent = bPermanent; bAlliancesChanged = True; bNoNegativeAlliances = False; } // ---------------------------------------------------------------------- // AgitateAlliance() // ---------------------------------------------------------------------- function AgitateAlliance(Name newEnemy, float agitation) { local int i; local float oldLevel; local float newLevel; if (newEnemy != '') { for (i=0; i<16; i++) if ((AlliancesEx[i].AllianceName == newEnemy) || (AlliancesEx[i].AllianceName == '')) break; if (i < 16) { if ((AlliancesEx[i].AllianceName == '') || !(AlliancesEx[i].bPermanent)) { if (AlliancesEx[i].AllianceName == '') AlliancesEx[i].AllianceLevel = 0; oldLevel = AlliancesEx[i].AgitationLevel; newLevel = oldLevel + agitation; if (newLevel > 1.0) newLevel = 1.0; AlliancesEx[i].AllianceName = newEnemy; AlliancesEx[i].AgitationLevel = newLevel; if ((newEnemy == 'Player') && (oldLevel < 1.0) && (newLevel >= 1.0)) // hack PlayerAgitationTimer = 2.0; bAlliancesChanged = True; } } } } // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // ATTACKING FUNCTIONS // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // AISafeToShoot() // ---------------------------------------------------------------------- function bool AISafeToShoot(out Actor hitActor, vector traceEnd, vector traceStart, optional vector extent, optional bool bIgnoreLevel) { local Actor traceActor; local Vector hitLocation; local Vector hitNormal; local Pawn tracePawn; local DeusExDecoration traceDecoration; local DeusExMover traceMover; local bool bSafe; // Future improvement: // Ideally, this should use the ammo type to determine how many shots // it will take to destroy an obstruction, and call it unsafe if it takes // more than x shots. Also, if the ammo is explosive, and the // obstruction is too close, it should never be safe... bSafe = true; hitActor = None; foreach TraceActors(Class'Actor', traceActor, hitLocation, hitNormal, traceEnd, traceStart, extent) { if (hitActor == None) hitActor = traceActor; if (traceActor == Level) { if (!bIgnoreLevel) bSafe = false; break; } tracePawn = Pawn(traceActor); if (tracePawn != None) { if (tracePawn != self) { if (GetPawnAllianceType(tracePawn) == ALLIANCE_Friendly) bSafe = false; break; } } traceDecoration = DeusExDecoration(traceActor); if (traceDecoration != None) { if (traceDecoration.bExplosive || traceDecoration.bInvincible) { bSafe = false; break; } if ((traceDecoration.HitPoints > 20) || (traceDecoration.minDamageThreshold > 4)) // hack { bSafe = false; break; } } traceMover = DeusExMover(traceActor); if (traceMover != None) { if (!traceMover.bBreakable) { bSafe = false; break; } else if ((traceMover.doorStrength > 0.2) || (traceMover.minDamageThreshold > 8)) // hack { bSafe = false; break; } else // hack break; } if (Inventory(traceActor) != None) { bSafe = false; break; } } return (bSafe); } // ---------------------------------------------------------------------- // ComputeThrowAngles() // ---------------------------------------------------------------------- function bool ComputeThrowAngles(vector traceEnd, vector traceStart, float speed, out Rotator angle1, out Rotator angle2) { local float deltaX, deltaY; local float x, y; local float tanAngle1, tanAngle2; local float A, B, C; local float m, n; local float sqrtTerm; local float gravity; local float traceYaw; local bool bValid; bValid = false; // Reduce our problem to two dimensions deltaX = traceEnd.X - traceStart.X; deltaY = traceEnd.Y - traceStart.Y; x = sqrt(deltaX*deltaX + deltaY*deltaY); y = traceEnd.Z - traceStart.Z; gravity = -Region.Zone.ZoneGravity.Z; if ((x > 0) && (gravity > 0)) { A = -gravity*x*x; B = 2*speed*speed*x; C = -gravity*x*x - 2*y*speed*speed; sqrtTerm = B*B - 4*A*C; if (sqrtTerm >= 0) { m = -B/(2*A); n = sqrt(sqrtTerm)/(2*A); tanAngle1 = atan(m+n); tanAngle2 = atan(m-n); angle1 = Rotator(traceEnd - traceStart); angle2 = angle1; angle1.Pitch = tanAngle1*32768/Pi; angle2.Pitch = tanAngle2*32768/Pi; bValid = true; } } return bValid; } // ---------------------------------------------------------------------- // AISafeToThrow() // ---------------------------------------------------------------------- function bool AISafeToThrow(vector traceEnd, vector traceStart, float throwAccuracy, optional vector extent) { local float time1, time2, tempTime; local vector pos1, pos2, tempPos; local rotator rot1, rot2, tempRot; local rotator bestAngle; local bool bSafe; local DeusExWeapon dxWeapon; local Class<ThrownProjectile> throwClass; // Someday, we should check for nearby friendlies within the blast radius // before throwing... // Sanity checks throwClass = None; dxWeapon = DeusExWeapon(Weapon); if (dxWeapon != None) throwClass = Class<ThrownProjectile>(dxWeapon.ProjectileClass); if (throwClass == None) return false; if (extent == vect(0,0,0)) { extent = vect(1,1,0) * throwClass.Default.CollisionRadius; extent.Z = throwClass.Default.CollisionHeight; } if (throwAccuracy < 0.01) throwAccuracy = 0.01; bSafe = false; if (ComputeThrowAngles(traceEnd, traceStart, dxWeapon.ProjectileSpeed, rot1, rot2)) { time1 = ParabolicTrace(pos1, Vector(rot1)*dxWeapon.ProjectileSpeed, traceStart, true, extent, 5.0, throwClass.Default.Elasticity, throwClass.Default.bBounce, 60, throwAccuracy); time2 = ParabolicTrace(pos2, Vector(rot2)*dxWeapon.ProjectileSpeed, traceStart, true, extent, 5.0, throwClass.Default.Elasticity, throwClass.Default.bBounce, 60, throwAccuracy); if ((time1 > 0) || (time2 > 0)) { if ((time1 > time2) && (time2 > 0)) { tempTime = time1; time1 = time2; time2 = tempTime; tempPos = pos1; pos1 = pos2; pos2 = tempPos; tempRot = rot1; rot1 = rot2; rot2 = tempRot; } if (VSize(pos1-traceEnd) <= throwClass.Default.blastRadius) { if (FastTrace(traceEnd, pos1)) { if ((VSize(pos1-Location) > throwClass.Default.blastRadius*0.5) || !FastTrace(Location, pos1)) { bestAngle = rot1; bSafe = true; } } } } if (!bSafe && (time2 > 0)) { if (VSize(pos2-traceEnd) <= throwClass.Default.blastRadius) { if (FastTrace(traceEnd, pos2)) { if ((VSize(pos2-Location) > throwClass.Default.blastRadius*0.5) || !FastTrace(Location, pos2)) { bestAngle = rot2; bSafe = true; } } } } } if (bSafe) ViewRotation = bestAngle; return (bSafe); } // ---------------------------------------------------------------------- // AICanShoot() // ---------------------------------------------------------------------- function bool AICanShoot(pawn target, bool bLeadTarget, bool bCheckReadiness, optional float throwAccuracy, optional bool bDiscountMinRange) { local DeusExWeapon dxWeapon; local Vector X, Y, Z; local Vector projStart, projEnd; local float tempMinRange, tempMaxRange; local float temp; local float dist; local float extraDist; local actor hitActor; local Vector hitLocation, hitNormal; local Vector extent; local bool bIsThrown; local float elevation; local bool bSafe; if (target == None) return false; if (target.bIgnore) return false; dxWeapon = DeusExWeapon(Weapon); if (dxWeapon == None) return false; if (bCheckReadiness && !dxWeapon.bReadyToFire) return false; if (dxWeapon.ReloadCount > 0) { if (dxWeapon.AmmoType == None) return false; if (dxWeapon.AmmoType.AmmoAmount <= 0) return false; } if (FireElevation > 0) { elevation = FireElevation + (CollisionHeight+target.CollisionHeight); if (elevation < 10) elevation = 10; if (Abs(Location.Z-target.Location.Z) > elevation) return false; } bIsThrown = IsThrownWeapon(dxWeapon); extraDist = target.CollisionRadius; //extraDist = 0; GetPawnWeaponRanges(self, tempMinRange, tempMaxRange, temp); if (bDiscountMinRange) tempMinRange = 0; if (tempMinRange >= tempMaxRange) return false; ViewRotation = Rotation; GetAxes(ViewRotation, X, Y, Z); projStart = dxWeapon.ComputeProjectileStart(X, Y, Z); if (bLeadTarget && !dxWeapon.bInstantHit && (dxWeapon.ProjectileSpeed > 0)) { if (bIsThrown) { // compute target's position 1.5 seconds in the future projEnd = target.Location + (target.Velocity*1.5); } else { // projEnd = target.Location + (target.Velocity*dist/dxWeapon.ProjectileSpeed); if (!ComputeTargetLead(target, projStart, dxWeapon.ProjectileSpeed, 5.0, projEnd)) return false; } } else projEnd = target.Location; if (bIsThrown) projEnd += vect(0,0,-1)*(target.CollisionHeight-5); dist = VSize(projEnd - Location); if (dist < 0) dist = 0; if ((dist < tempMinRange) || (dist-extraDist > tempMaxRange)) return false; if (!bIsThrown) { bSafe = FastTrace(target.Location, projStart); if (!bSafe && target.bIsPlayer) // players only... hack { projEnd += vect(0,0,1)*target.BaseEyeHeight; bSafe = FastTrace(target.Location + vect(0,0,1)*target.BaseEyeHeight, projStart); } if (!bSafe) return false; } if (dxWeapon.bInstantHit) return (AISafeToShoot(hitActor, projEnd, projStart, , true)); else { extent.X = dxWeapon.ProjectileClass.default.CollisionRadius; extent.Y = dxWeapon.ProjectileClass.default.CollisionRadius; extent.Z = dxWeapon.ProjectileClass.default.CollisionHeight; if (bIsThrown && (throwAccuracy > 0)) return (AISafeToThrow(projEnd, projStart, throwAccuracy, extent)); else return (AISafeToShoot(hitActor, projEnd, projStart, extent*3)); } } // ---------------------------------------------------------------------- // ComputeTargetLead() // ---------------------------------------------------------------------- function bool ComputeTargetLead(pawn target, vector projectileStart, float projectileSpeed, float maxTime, out Vector hitPos) { local vector targetLoc; local vector targetVel; local float termA, termB, termC; local float temp; local float base, range; local float time1, time2; local bool bSuccess; bSuccess = true; targetLoc = target.Location - projectileStart; targetVel = target.Velocity; if (target.Physics == PHYS_Falling) targetVel.Z = 0; // Given a target position and velocity, and a projectile speed, // compute the position at which a projectile will hit the // target if the target continues at its current velocity // (Warning: messy computations follow. I can't believe I remembered // enough algebra to figure this out on my own... :) termA = targetVel.X*targetVel.X + targetVel.Y*targetVel.Y + targetVel.Z*targetVel.Z - projectileSpeed*projectileSpeed; termB = 2*targetLoc.X*targetVel.X + 2*targetLoc.Y*targetVel.Y + 2*targetLoc.Z*targetVel.Z; termC = targetLoc.X*targetLoc.X + targetLoc.Y*targetLoc.Y + targetLoc.Z*targetLoc.Z; if ((termA < 0.000001) && (termA > -0.000001)) // avoid divide-by-zero errors... termA = 0.000001; // fudge a little when velocities are equal temp = termB*termB - 4*termA*termC; if (temp < 0) bSuccess = false; if (bSuccess) { base = -termB/(2*termA); range = sqrt(temp)/(2*termA); time1 = base+range; time2 = base-range; if ((time1 > time2) || (time1 < 0)) // best time first time1 = time2; if ((time1 < 0) || (time1 >= maxTime)) bSuccess = false; } if (bSuccess) hitPos = target.Location + target.Velocity*time1; return (bSuccess); } // ---------------------------------------------------------------------- // GetPawnWeaponRanges() // ---------------------------------------------------------------------- function GetPawnWeaponRanges(Pawn other, out float minRange, out float maxAccurateRange, out float maxRange) { local DeusExWeapon pawnWeapon; local Class<DeusExProjectile> projectileClass; pawnWeapon = DeusExWeapon(other.Weapon); if (pawnWeapon != None) { pawnWeapon.GetWeaponRanges(minRange, maxAccurateRange, maxRange); if (IsThrownWeapon(pawnWeapon)) // hack minRange = 0; } else { minRange = 0; maxAccurateRange = other.CollisionRadius; maxRange = maxAccurateRange; } if (maxAccurateRange > maxRange) maxAccurateRange = maxRange; if (minRange > maxRange) minRange = maxRange; } // ---------------------------------------------------------------------- // GetWeaponBestRange() // ---------------------------------------------------------------------- function GetWeaponBestRange(DeusExWeapon dxWeapon, out float bestRangeMin, out float bestRangeMax) { local float temp; local float minRange, maxRange; local float AIMinRange, AIMaxRange; if (dxWeapon != None) { dxWeapon.GetWeaponRanges(minRange, maxRange, temp); if (IsThrownWeapon(dxWeapon)) // hack minRange = 0; AIMinRange = dxWeapon.AIMinRange; AIMaxRange = dxWeapon.AIMaxRange; if ((AIMinRange > 0) && (AIMinRange >= minRange) && (AIMinRange <= maxRange)) bestRangeMin = AIMinRange; else bestRangeMin = minRange; if ((AIMaxRange > 0) && (AIMaxRange >= minRange) && (AIMaxRange <= maxRange)) bestRangeMax = AIMaxRange; else bestRangeMax = maxRange; if (bestRangeMin > bestRangeMax) bestRangeMin = bestRangeMax; } else { bestRangeMin = 0; bestRangeMax = 0; } } // ---------------------------------------------------------------------- // ReadyForNewEnemy() // ---------------------------------------------------------------------- function bool ReadyForNewEnemy() { if ((Enemy == None) || (EnemyTimer > 5.0)) return True; else return False; } // ---------------------------------------------------------------------- // CheckEnemyParams() [internal use only] // ---------------------------------------------------------------------- function CheckEnemyParams(Pawn checkPawn, out Pawn bestPawn, out int bestThreatLevel, out float bestDist) { local ScriptedPawn sPawn; local bool bReplace; local float dist; local int threatLevel; local bool bValid; bValid = IsValidEnemy(checkPawn); if (bValid && (Enemy != checkPawn)) { // Honor cloaking, radar transparency, and other augs if this guy isn't our current enemy if (ComputeActorVisibility(checkPawn) < 0.1) bValid = false; } if (bValid) { sPawn = ScriptedPawn(checkPawn); dist = VSize(checkPawn.Location - Location); if (checkPawn.IsA('Robot')) dist *= 0.5; // arbitrary if (Enemy == checkPawn) dist *= 0.75; // arbitrary if (sPawn != None) { if (sPawn.bAttacking) { if (sPawn.Enemy == self) threatLevel = 2; else threatLevel = 1; } else if (sPawn.GetStateName() == 'Alerting') threatLevel = 3; else if ((sPawn.GetStateName() == 'Fleeing') || (sPawn.GetStateName() == 'Burning')) threatLevel = 0; else if (sPawn.Weapon != None) threatLevel = 1; else threatLevel = 0; } else // player { if (checkPawn.Weapon != None) threatLevel = 2; else threatLevel = 1; } bReplace = false; if (bestPawn == None) bReplace = true; else if (bestThreatLevel < threatLevel) bReplace = true; else if (bestDist > dist) bReplace = true; if (bReplace) { if ((Enemy == checkPawn) || (AICanSee(checkPawn, , false, false, true, true) > 0)) { bestPawn = checkPawn; bestThreatLevel = threatLevel; bestDist = dist; } } } } // ---------------------------------------------------------------------- // FindBestEnemy() // ---------------------------------------------------------------------- function FindBestEnemy(bool bIgnoreCurrentEnemy) { local Pawn nextPawn; local Pawn bestPawn; local float bestDist; local int bestThreatLevel; local float newSeenTime; bestPawn = None; bestDist = 0; bestThreatLevel = 0; if (!bIgnoreCurrentEnemy && (Enemy != None)) CheckEnemyParams(Enemy, bestPawn, bestThreatLevel, bestDist); foreach RadiusActors(Class'Pawn', nextPawn, 2000) // arbitrary if (enemy != nextPawn) CheckEnemyParams(nextPawn, bestPawn, bestThreatLevel, bestDist); if (bestPawn != Enemy) newSeenTime = 0; else newSeenTime = EnemyLastSeen; SetEnemy(bestPawn, newSeenTime, true); EnemyTimer = 0; } // ---------------------------------------------------------------------- // ShouldStrafe() // ---------------------------------------------------------------------- function bool ShouldStrafe() { // This may be overridden from subclasses //return (AICanSee(enemy, 1.0, false, true, true, true) > 0); return (AICanShoot(enemy, false, false, 0.025, true)); } // ---------------------------------------------------------------------- // ShouldFlee() // ---------------------------------------------------------------------- function bool ShouldFlee() { // This may be overridden from subclasses if (MinHealth > 0) { if (Health <= MinHealth) return true; else if (HealthArmLeft <= 0) return true; else if (HealthArmRight <= 0) return true; else if (HealthLegLeft <= 0) return true; else if (HealthLegRight <= 0) return true; else return false; } else return false; } // ---------------------------------------------------------------------- // ShouldDropWeapon() // ---------------------------------------------------------------------- function bool ShouldDropWeapon() { if (((HealthArmLeft <= 0) || (HealthArmRight <= 0)) && (Health > 0)) return true; else return false; } // ---------------------------------------------------------------------- // TryLocation() // ---------------------------------------------------------------------- function bool TryLocation(out vector position, optional float minDist, optional bool bTraceActors, optional NearbyProjectileList projList) { local float magnitude; local vector normalPos; local Rotator rot; local float dist; local bool bSuccess; normalPos = position-Location; magnitude = VSize(normalPos); if (minDist > magnitude) minDist = magnitude; rot = Rotator(position-Location); bSuccess = AIDirectionReachable(Location, rot.Yaw, rot.Pitch, minDist, magnitude, position); if (bSuccess) { if (bDefendHome && !IsNearHome(position)) bSuccess = false; else if (bAvoidHarm && IsLocationDangerous(projList, position)) bSuccess = false; } return (bSuccess); } // ---------------------------------------------------------------------- // ComputeBestFiringPosition() // ---------------------------------------------------------------------- function EDestinationType ComputeBestFiringPosition(out vector newPosition) { local float selfMinRange, selfMaxRange; local float enemyMinRange, enemyMaxRange; local float temp; local float dist; local float innerRange[2], outerRange[2]; local Rotator relativeRotation; local float hAngle, vAngle; local int acrossDist; local float awayDist; local float extraDist; local float fudgeMargin; local int angle; local float maxDist; local float distDelta; local bool bInnerValid, bOuterValid; local vector tryVector; local EDestinationType destType; local float moveMult; local float reloadMult; local float minArea; local float minDist; local float range; local float margin; local NearbyProjectileList projList; local vector projVector; local bool bUseProjVector; local rotator sprintRot; local vector sprintVect; local bool bUseSprint; destType = DEST_Failure; extraDist = enemy.CollisionRadius*0.5; fudgeMargin = 100; minArea = 35; GetPawnWeaponRanges(self, selfMinRange, selfMaxRange, temp); GetPawnWeaponRanges(enemy, enemyMinRange, temp, enemyMaxRange); if (selfMaxRange > 1200) selfMaxRange = 1200; if (enemyMaxRange > 1200) enemyMaxRange = 1200; // hack, to prevent non-strafing NPCs from trying to back up if (!bCanStrafe) selfMinRange = 0; minDist = enemy.CollisionRadius + CollisionRadius - (extraDist+1); if (selfMinRange < minDist) selfMinRange = minDist; if (selfMinRange < MinRange) selfMinRange = MinRange; if (selfMaxRange > MaxRange) selfMaxRange = MaxRange; dist = VSize(enemy.Location-Location); innerRange[0] = selfMinRange; innerRange[1] = selfMaxRange; outerRange[0] = selfMinRange; outerRange[1] = selfMaxRange; // hack, to prevent non-strafing NPCs from trying to back up if (selfMaxRange > enemyMinRange) innerRange[1] = enemyMinRange; if ((selfMinRange < enemyMaxRange) && bCanStrafe) // hack, to prevent non-strafing NPCs from trying to back up outerRange[0] = enemyMaxRange; range = outerRange[1]-outerRange[0]; if (range < minArea) { outerRange[0] = 0; outerRange[1] = 0; } range = innerRange[1]-innerRange[0]; if (range < minArea) { innerRange[0] = outerRange[0]; innerRange[1] = outerRange[1]; outerRange[0] = 0; outerRange[1] = 0; } // If the enemy can reach us through our entire weapon range, just use the range if ((innerRange[0] >= innerRange[1]) && (outerRange[0] >= outerRange[1])) { innerRange[0] = selfMinRange; innerRange[1] = selfMaxRange; } innerRange[0] += extraDist; innerRange[1] += extraDist; outerRange[0] += extraDist; outerRange[1] += extraDist; if (innerRange[0] >= innerRange[1]) bInnerValid = false; else bInnerValid = true; if (outerRange[0] >= outerRange[1]) bOuterValid = false; else bOuterValid = true; if (!bInnerValid) { // ugly newPosition = Location; // return DEST_SameLocation; return destType; } relativeRotation = Rotator(Location - enemy.Location); hAngle = (relativeRotation.Yaw - enemy.Rotation.Yaw) & 65535; if (hAngle > 32767) hAngle -= 65536; // ignore vertical angle for now awayDist = dist; acrossDist = 0; maxDist = GroundSpeed*0.6; // distance covered in 6/10 second if (bInnerValid) { margin = (innerRange[1]-innerRange[0]) * 0.5; if (margin > fudgeMargin) margin = fudgeMargin; if (awayDist < innerRange[0]) awayDist = innerRange[0]+margin; else if (awayDist > innerRange[1]) awayDist = innerRange[1]-margin; } if (bOuterValid) { margin = (outerRange[1]-outerRange[0]) * 0.5; if (margin > fudgeMargin) margin = fudgeMargin; if (awayDist > outerRange[1]) awayDist = outerRange[1]-margin; } if (awayDist > dist+maxDist) awayDist = dist+maxDist; if (awayDist < dist-maxDist) awayDist = dist-maxDist; // Used to determine whether NPCs should sprint/avoid aim moveMult = 1.0; if ((dist <= 180) && enemy.bIsPlayer && (enemy.Weapon != None) && (enemyMaxRange < 180)) moveMult = CloseCombatMult; if (bAvoidAim && !enemy.bIgnore && (FRand() <= AvoidAccuracy*moveMult)) { if ((awayDist < enemyMaxRange+maxDist+50) && (awayDist < 800) && (Enemy.Weapon != None)) { if (dist > 0) angle = int(atan(CollisionRadius*2.0/dist)*32768/Pi); else angle = 16384; if ((hAngle >= -angle) && (hAngle <= angle)) { if (hAngle < 0) acrossDist = (-angle-hAngle)-128; else acrossDist = (angle-hAngle)+128; if (Rand(20) == 0) acrossDist = -acrossDist; } } } // projList is implicitly initialized to null... bUseProjVector = false; if (bAvoidHarm && (FRand() <= HarmAccuracy)) { if (GetProjectileList(projList, Location) > 0) { if (IsLocationDangerous(projList, Location)) { projVector = ComputeAwayVector(projList); bUseProjVector = true; } } } reloadMult = 1.0; if (IsWeaponReloading() && Enemy.bIsPlayer) reloadMult = 0.5; bUseSprint = false; if (!bUseProjVector && bSprint && bCanStrafe && !enemy.bIgnore && (FRand() <= SprintRate*0.5*moveMult*reloadMult)) { if (bOuterValid || (innerRange[1] > 100)) // sprint on long-range weapons only { sprintRot = Rotator(enemy.Location - Location); if (Rand(2) == 1) sprintRot.Yaw += 16384; else sprintRot.Yaw += 49152; sprintRot = RandomBiasedRotation(sprintRot.Yaw, 0.5, 0, 0); sprintRot.Pitch = 0; sprintVect = Vector(sprintRot)*GroundSpeed*(FRand()+0.5); bUseSprint = true; } } if ((acrossDist != 0) || (awayDist != dist) || bUseProjVector || bUseSprint) { if (Rand(40) != 0) { if ((destType == DEST_Failure) && bUseProjVector) { tryVector = projVector + Location; if (TryLocation(tryVector, CollisionRadius+16)) destType = DEST_NewLocation; } if ((destType == DEST_Failure) && (acrossDist != 0) && (awayDist != dist)) { tryVector = Vector(relativeRotation+(rot(0, 1, 0)*acrossDist))*awayDist + enemy.Location; if (TryLocation(tryVector, CollisionRadius+16, , projList)) destType = DEST_NewLocation; } if ((destType == DEST_Failure) && (awayDist != dist)) { tryVector = Vector(relativeRotation)*awayDist + enemy.Location; if (TryLocation(tryVector, CollisionRadius+16, , projList)) destType = DEST_NewLocation; } if ((destType == DEST_Failure) && (acrossDist != 0)) { tryVector = Vector(relativeRotation+(rot(0, 1, 0)*acrossDist))*dist + enemy.Location; if (TryLocation(tryVector, CollisionRadius+16, , projList)) destType = DEST_NewLocation; } if ((destType == DEST_Failure) && bUseSprint) { tryVector = sprintVect + Location; if (TryLocation(tryVector, CollisionRadius+16)) destType = DEST_NewLocation; } } if (destType == DEST_Failure) { if ((moveMult >= 0.5) || (FRand() <= moveMult)) { if (AIPickRandomDestination(CollisionRadius+16, maxDist, relativeRotation.Yaw+32768, 0.6, -relativeRotation.Pitch, 0.6, 2, 0.9, tryVector)) if (!bDefendHome || IsNearHome(tryVector)) if (!bAvoidHarm || !IsLocationDangerous(projList, tryVector)) destType = DEST_NewLocation; } else destType = DEST_SameLocation; } if (destType != DEST_Failure) newPosition = tryVector; } else destType = DEST_SameLocation; return destType; } // ---------------------------------------------------------------------- // SetAttackAngle() // // Sets the angle from which an asynchronous attack will occur // (hack needed for DeusExWeapon) // ---------------------------------------------------------------------- function SetAttackAngle() { local bool bCanShoot; bCanShoot = false; if (Enemy != None) if (AICanShoot(Enemy, true, false, 0.025)) bCanShoot = true; if (!bCanShoot) ViewRotation = Rotation; } // ---------------------------------------------------------------------- // AdjustAim() // // Adjust the aim at target // ---------------------------------------------------------------------- function rotator AdjustAim(float projSpeed, vector projStart, int aimerror, bool leadTarget, bool warnTarget) { local rotator FireRotation; local vector FireSpot; local actor HitActor; local vector HitLocation, HitNormal; local vector vectorArray[3]; local vector tempVector; local int i; local int swap; local Rotator rot; local bool bIsThrown; local DeusExMover dxMover; local actor Target; // evil fix -- STM bIsThrown = IsThrownWeapon(DeusExWeapon(Weapon)); // took this line out for evil fix... // if ( Target == None ) Target = Enemy; if ( Target == None ) return Rotation; if ( !Target.IsA('Pawn') ) return rotator(Target.Location - Location); FireSpot = Target.Location; if (leadTarget && (projSpeed > 0)) { if (bIsThrown) { // compute target's position 1.5 seconds in the future FireSpot = target.Location + (target.Velocity*1.5); } else { //FireSpot += (Target.Velocity * VSize(Target.Location - ProjStart)/projSpeed); ComputeTargetLead(Pawn(Target), ProjStart, projSpeed, 20.0, FireSpot); } } if (bIsThrown) { vectorArray[0] = FireSpot - vect(0,0,1)*(Target.CollisionHeight-5); // floor vectorArray[1] = vectorArray[0] + Vector(rot(0,1,0)*Rand(65536))*CollisionRadius*1.2; vectorArray[2] = vectorArray[0] + Vector(rot(0,1,0)*Rand(65536))*CollisionRadius*1.2; for (i=0; i<3; i++) { if (AISafeToThrow(vectorArray[i], ProjStart, 0.025)) break; } if (i < 3) { FireSpot = vectorArray[i]; FireRotation = ViewRotation; } else FireRotation = Rotator(FireSpot - ProjStart); } else { dxMover = DeusExMover(Target.Base); if ((dxMover != None) && dxMover.bBreakable) { tempVector = Normal((Location-Target.Location)*vect(1,1,0))*(Target.CollisionRadius*1.01) - vect(0,0,1)*(Target.CollisionHeight*1.01); vectorArray[0] = FireSpot + tempVector; } else if (bAimForHead) vectorArray[0] = FireSpot + vect(0,0,1)*(Target.CollisionHeight*0.85); // head else vectorArray[0] = FireSpot + vect(0,0,1)*((FRand()*2-1)*Target.CollisionHeight); vectorArray[1] = FireSpot + vect(0,0,1)*((FRand()*2-1)*Target.CollisionHeight); vectorArray[2] = FireSpot + vect(0,0,1)*((FRand()*2-1)*Target.CollisionHeight); for (i=0; i<3; i++) { if (AISafeToShoot(HitActor, vectorArray[i], ProjStart)) break; } if (i < 3) FireSpot = vectorArray[i]; FireRotation = Rotator(FireSpot - ProjStart); } if (warnTarget && Pawn(Target) != None) Pawn(Target).WarnTarget(self, projSpeed, vector(FireRotation)); FireRotation.Yaw = FireRotation.Yaw & 65535; if ( (Abs(FireRotation.Yaw - (Rotation.Yaw & 65535)) > 8192) && (Abs(FireRotation.Yaw - (Rotation.Yaw & 65535)) < 57343) ) { if ( (FireRotation.Yaw > Rotation.Yaw + 32768) || ((FireRotation.Yaw < Rotation.Yaw) && (FireRotation.Yaw > Rotation.Yaw - 32768)) ) FireRotation.Yaw = Rotation.Yaw - 8192; else FireRotation.Yaw = Rotation.Yaw + 8192; } viewRotation = FireRotation; return FireRotation; } // ---------------------------------------------------------------------- // IsThrownWeapon() // ---------------------------------------------------------------------- function bool IsThrownWeapon(DeusExWeapon testWeapon) { local Class<ThrownProjectile> throwClass; local bool bIsThrown; bIsThrown = false; if (testWeapon != None) { if (!testWeapon.bInstantHit) { throwClass = class<ThrownProjectile>(testWeapon.ProjectileClass); if (throwClass != None) bIsThrown = true; } } return bIsThrown; } // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // CALLBACKS AND OVERRIDDEN FUNCTIONS // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // Tick() // ---------------------------------------------------------------------- function Tick(float deltaTime) { local float dropPeriod; local float adjustedRate; local DeusExPlayer player; local name stateName; local vector loc; local bool bDoLowPriority; local bool bCheckOther; local bool bCheckPlayer; player = DeusExPlayer(GetPlayerPawn()); bDoLowPriority = true; bCheckPlayer = true; bCheckOther = true; if (bTickVisibleOnly) { if (DistanceFromPlayer > 1200) bDoLowPriority = false; if (DistanceFromPlayer > 2500) bCheckPlayer = false; if ((DistanceFromPlayer > 600) && (LastRendered() >= 5.0)) bCheckOther = false; } /* if (bDisappear && (InStasis() || (LastRendered() > 5.0))) { Destroy(); return; } if (PrePivotTime > 0) { if (deltaTime < PrePivotTime) { PrePivot = PrePivot + (DesiredPrePivot-PrePivot)*deltaTime/PrePivotTime; PrePivotTime -= deltaTime; } else { PrePivot = DesiredPrePivot; PrePivotTime = 0; } } if (bDoLowPriority) Super.Tick(deltaTime); UpdateAgitation(deltaTime); UpdateFear(deltaTime); AlarmTimer -= deltaTime; if (AlarmTimer < 0) AlarmTimer = 0; if (Weapon != None) WeaponTimer += deltaTime; else if (WeaponTimer != 0) WeaponTimer = 0; if ((ReloadTimer > 0) && (Weapon != None)) ReloadTimer -= deltaTime; else ReloadTimer = 0; if (AvoidWallTimer > 0) { AvoidWallTimer -= deltaTime; if (AvoidWallTimer < 0) AvoidWallTimer = 0; } if (AvoidBumpTimer > 0) { AvoidBumpTimer -= deltaTime; if (AvoidBumpTimer < 0) AvoidBumpTimer = 0; } if (CloakEMPTimer > 0) { CloakEMPTimer -= deltaTime; if (CloakEMPTimer < 0) CloakEMPTimer = 0; } if (TakeHitTimer > 0) { TakeHitTimer -= deltaTime; if (TakeHitTimer < 0) TakeHitTimer = 0; } if (CarcassCheckTimer > 0) { CarcassCheckTimer -= deltaTime; if (CarcassCheckTimer < 0) CarcassCheckTimer = 0; } if (PotentialEnemyTimer > 0) { PotentialEnemyTimer -= deltaTime; if (PotentialEnemyTimer <= 0) { PotentialEnemyTimer = 0; PotentialEnemyAlliance = ''; } } if (BeamCheckTimer > 0) { BeamCheckTimer -= deltaTime; if (BeamCheckTimer < 0) BeamCheckTimer = 0; } if (FutzTimer > 0) { FutzTimer -= deltaTime; if (FutzTimer < 0) FutzTimer = 0; } if (PlayerAgitationTimer > 0) { PlayerAgitationTimer -= deltaTime; if (PlayerAgitationTimer < 0) PlayerAgitationTimer = 0; } if (DistressTimer >= 0) { DistressTimer += deltaTime; if (DistressTimer > FearSustainTime) DistressTimer = -1; } if (bHasCloak) EnableCloak(Health <= CloakThreshold); if (bAdvancedTactics) { if ((Acceleration == vect(0,0,0)) || (Physics != PHYS_Walking) || (TurnDirection == TURNING_None)) { bAdvancedTactics = false; if (TurnDirection != TURNING_None) MoveTimer -= 4.0; ActorAvoiding = None; NextDirection = TURNING_None; TurnDirection = TURNING_None; bClearedObstacle = true; ObstacleTimer = 0; } } if (bOnFire) { burnTimer += deltaTime; if (burnTimer >= BurnPeriod) ExtinguishFire(); } if (bDoLowPriority) { if ((bleedRate > 0) && bCanBleed) { adjustedRate = (1.0-FClamp(bleedRate, 0.0, 1.0))*1.0+0.1; // max 10 drops per second dropPeriod = adjustedRate / FClamp(VSize(Velocity)/512.0, 0.05, 1.0); dropCounter += deltaTime; while (dropCounter >= dropPeriod) { SpurtBlood(); dropCounter -= dropPeriod; } bleedRate -= deltaTime/clotPeriod; } if (bleedRate <= 0) { dropCounter = 0; bleedRate = 0; } } */ if (bStandInterpolation) UpdateStanding(deltaTime); // this is UGLY! if (bOnFire && (health > 0)) { stateName = GetStateName(); if ((stateName != 'Burning') && (stateName != 'TakingHit') && (stateName != 'RubbingEyes')) GotoState('Burning'); } else { if (bDoLowPriority) { // Don't allow radius-based convos to interupt other conversations! if ((player != None) && (GetStateName() != 'Conversation') && (GetStateName() != 'FirstPersonConversation')) player.StartConversation(Self, IM_Radius); } if (CheckEnemyPresence(deltaTime, bCheckPlayer, bCheckOther)) HandleEnemy(); else { CheckBeamPresence(deltaTime); if (bDoLowPriority || LastRendered() < 5.0) CheckCarcassPresence(deltaTime); // hacky -- may change state! } } // Randomly spawn an air bubble every 0.2 seconds if we're underwater if (HeadRegion.Zone.bWaterZone && bSpawnBubbles && bDoLowPriority) { swimBubbleTimer += deltaTime; if (swimBubbleTimer >= 0.2) { swimBubbleTimer = 0; if (FRand() < 0.4) { loc = Location + VRand() * 4; loc.Z += CollisionHeight * 0.9; Spawn(class'AirBubble', Self,, loc); } } } // Handle poison damage UpdatePoison(deltaTime); } // ---------------------------------------------------------------------- // SpurtBlood() // ---------------------------------------------------------------------- function SpurtBlood() { local vector bloodVector; bloodVector = vect(0,0,1)*CollisionHeight*0.5; // so folks don't bleed from the crotch spawn(Class'BloodDrop',,,bloodVector+Location); } // ---------------------------------------------------------------------- // TakeDamage() // ---------------------------------------------------------------------- function TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { TakeDamageBase(Damage, instigatedBy, hitlocation, momentum, damageType, true); } // ---------------------------------------------------------------------- // Timer() // ---------------------------------------------------------------------- function Timer() { UpdateFire(); } // ---------------------------------------------------------------------- // ZoneChange() // ---------------------------------------------------------------------- function ZoneChange(ZoneInfo newZone) { local vector jumpDir; if (!bInWorld) return; if (newZone.bWaterZone) { EnableShadow(false); if (!bCanSwim) MoveTimer = -1.0; else if (Physics != PHYS_Swimming) { if (bOnFire) ExtinguishFire(); PlaySwimming(); setPhysics(PHYS_Swimming); } swimBubbleTimer = 0; } else if (Physics == PHYS_Swimming) { EnableShadow(true); if ( bCanFly ) SetPhysics(PHYS_Flying); else { SetPhysics(PHYS_Falling); if ( bCanWalk && (Abs(Acceleration.X) + Abs(Acceleration.Y) > 0) && CheckWaterJump(jumpDir) ) JumpOutOfWater(jumpDir); } } } // ---------------------------------------------------------------------- // BaseChange() // ---------------------------------------------------------------------- singular function BaseChange() { Super.BaseChange(); if (bSitting && !IsSeatValid(SeatActor)) { StandUp(); if (GetStateName() == 'Sitting') GotoState('Sitting', 'Begin'); } } // ---------------------------------------------------------------------- // PainTimer() // ---------------------------------------------------------------------- event PainTimer() { local float depth; local PointRegion painRegion; if ((Health <= 0) || (Level.NetMode == NM_Client)) return; painRegion = HeadRegion; if (!painRegion.Zone.bPainZone || (painRegion.Zone.DamageType == ReducedDamageType)) painRegion = Region; if (!painRegion.Zone.bPainZone || (painRegion.Zone.DamageType == ReducedDamageType)) painRegion = FootRegion; if (painRegion.Zone.bPainZone && (painRegion.Zone.DamageType != ReducedDamageType)) { depth = 0; if (FootRegion.Zone.bPainZone) depth += 0.3; if (Region.Zone.bPainZone) depth += 0.3; if (HeadRegion.Zone.bPainZone) depth += 0.4; if (painRegion.Zone.DamagePerSec > 0) TakeDamage(int(float(painRegion.Zone.DamagePerSec) * depth), None, Location, vect(0,0,0), painRegion.Zone.DamageType); // took out healing for NPCs -- we don't use healing zones anyway /* else if ( Health < Default.Health ) Health = Min(Default.Health, Health - depth * FootRegion.Zone.DamagePerSec); */ if (Health > 0) PainTime = 1.0; } else if (HeadRegion.Zone.bWaterZone && (UnderWaterTime > 0)) { TakeDamage(5, None, Location, vect(0,0,0), 'Drowned'); if (Health > 0) PainTime = 2.0; } } // ---------------------------------------------------------------------- // CheckWaterJump() // ---------------------------------------------------------------------- function bool CheckWaterJump(out vector WallNormal) { local actor HitActor; local vector HitLocation, HitNormal, checkpoint, start, checkNorm, Extent; if (CarriedDecoration != None) return false; checkpoint = vector(Rotation); checkpoint.Z = 0.0; checkNorm = Normal(checkpoint); checkPoint = Location + CollisionRadius * checkNorm; Extent = CollisionRadius * vect(1,1,0); Extent.Z = CollisionHeight; HitActor = Trace(HitLocation, HitNormal, checkpoint, Location, false, Extent); if ( (HitActor != None) && (Pawn(HitActor) == None) ) { WallNormal = -1 * HitNormal; start = Location; start.Z += 1.1 * MaxStepHeight + CollisionHeight; checkPoint = start + 2 * CollisionRadius * checkNorm; HitActor = Trace(HitLocation, HitNormal, checkpoint, start, true, Extent); if (HitActor == None) return true; } return false; } // ---------------------------------------------------------------------- // SetMovementPhysics() // ---------------------------------------------------------------------- function SetMovementPhysics() { // re-implement SetMovementPhysics() in subclass for flying and swimming creatures if (Physics == PHYS_Falling) return; if (Region.Zone.bWaterZone && bCanSwim) SetPhysics(PHYS_Swimming); else if (Default.Physics == PHYS_None) SetPhysics(PHYS_Walking); else SetPhysics(Default.Physics); } // ---------------------------------------------------------------------- // PreSetMovement() // ---------------------------------------------------------------------- function PreSetMovement() { // Copied from Pawn.uc and overridden so Pawn doesn't erase our walking/swimming/flying physics if (JumpZ > 0) bCanJump = true; // No, no, no!!! /* bCanWalk = true; bCanSwim = false; bCanFly = false; MinHitWall = -0.6; if (Intelligence > BRAINS_Reptile) bCanOpenDoors = true; if (Intelligence == BRAINS_Human) bCanDoSpecial = true; */ } // ---------------------------------------------------------------------- // ChangedWeapon() // ---------------------------------------------------------------------- function ChangedWeapon() { // do nothing } // ---------------------------------------------------------------------- // SwitchToBestWeapon() // ---------------------------------------------------------------------- function bool SwitchToBestWeapon() { local Inventory inv; local DeusExWeapon curWeapon; local float score; local DeusExWeapon dxWeapon; local DeusExWeapon bestWeapon; local float bestScore; local int fallbackLevel; local int curFallbackLevel; local bool bBlockSpecial; local bool bValid; local bool bWinner; local float minRange, accRange; local float range, centerRange; local float cutoffRange; local float enemyRange; local float minEnemy, accEnemy, maxEnemy; local ScriptedPawn enemyPawn; local Robot enemyRobot; local DeusExPlayer enemyPlayer; local float enemyRadius; local bool bEnemySet; local int loopCount, i; // hack - check for infinite inventory local Inventory loopInv; // hack - check for infinite inventory if (ShouldDropWeapon()) { DropWeapon(); return false; } bBlockSpecial = false; dxWeapon = DeusExWeapon(Weapon); if (dxWeapon != None) { if (dxWeapon.AITimeLimit > 0) { if (SpecialTimer <= 0) { bBlockSpecial = true; FireTimer = dxWeapon.AIFireDelay; } } } bestWeapon = None; bestScore = 0; fallbackLevel = 0; inv = Inventory; bEnemySet = false; minEnemy = 0; accEnemy = 0; enemyRange = 400; // default enemyRadius = 0; enemyPawn = None; enemyRobot = None; if (Enemy != None) { bEnemySet = true; enemyRange = VSize(Enemy.Location - Location); enemyRadius = Enemy.CollisionRadius; if (DeusExWeapon(Enemy.Weapon) != None) DeusExWeapon(Enemy.Weapon).GetWeaponRanges(minEnemy, accEnemy, maxEnemy); enemyPawn = ScriptedPawn(Enemy); enemyRobot = Robot(Enemy); enemyPlayer = DeusExPlayer(Enemy); } loopCount = 0; while (inv != None) { // THIS IS A MAJOR HACK!!! loopCount++; if (loopCount == 9999) { log("********** RUNAWAY LOOP IN SWITCHTOBESTWEAPON ("$self$") **********"); loopInv = Inventory; i = 0; while (loopInv != None) { i++; if (i > 300) break; log(" Inventory "$i$" - "$loopInv); loopInv = loopInv.Inventory; } } curWeapon = DeusExWeapon(inv); if (curWeapon != None) { bValid = true; if (curWeapon.ReloadCount > 0) { if (curWeapon.AmmoType == None) bValid = false; else if (curWeapon.AmmoType.AmmoAmount < 1) bValid = false; } // Ensure we can actually use this weapon here if (bValid) { // lifted from DeusExWeapon... if ((curWeapon.EnviroEffective == ENVEFF_Air) || (curWeapon.EnviroEffective == ENVEFF_Vacuum) || (curWeapon.EnviroEffective == ENVEFF_AirVacuum)) if (curWeapon.Region.Zone.bWaterZone) bValid = false; } if (bValid) { GetWeaponBestRange(curWeapon, minRange, accRange); cutoffRange = minRange+(CollisionRadius+enemyRadius); range = (accRange - minRange) * 0.5; centerRange = minRange + range; if (range < 50) range = 50; if (enemyRange < centerRange) score = (centerRange - enemyRange)/range; else score = (enemyRange - centerRange)/range; if ((minRange >= minEnemy) && (accRange <= accEnemy)) score += 0.5; // arbitrary if ((cutoffRange >= enemyRange-CollisionRadius) && (cutoffRange >= 256)) // do not use long-range weapons on short-range targets score += 10000; curFallbackLevel = 3; if (curWeapon.bFallbackWeapon && !bUseFallbackWeapons) curFallbackLevel = 2; if (!bEnemySet && !curWeapon.bUseAsDrawnWeapon) curFallbackLevel = 1; if ((curWeapon.AIFireDelay > 0) && (FireTimer > 0)) curFallbackLevel = 0; if (bBlockSpecial && (curWeapon.AITimeLimit > 0) && (SpecialTimer <= 0)) curFallbackLevel = 0; // Adjust score based on opponent and damage type. // All damage types are listed here, even the ones that aren't used by weapons... :) // (hacky...) switch (curWeapon.WeaponDamageType()) { case 'Exploded': // Massive explosions are always good score -= 0.2; break; case 'Stunned': if (enemyPawn != None) { if (enemyPawn.bStunned) score += 1000; else score -= 1.5; } if (enemyPlayer != None) score += 10; break; case 'TearGas': if (enemyPawn != None) { if (enemyPawn.bStunned) //score += 1000; bValid = false; else score -= 5.0; } if (enemyRobot != None) //score += 10000; bValid = false; break; case 'HalonGas': if (enemyPawn != None) { if (enemyPawn.bStunned) //score += 1000; bValid = false; else if (enemyPawn.bOnFire) //score += 10000; bValid = false; else score -= 3.0; } if (enemyRobot != None) //score += 10000; bValid = false; break; case 'PoisonGas': case 'Poison': case 'PoisonEffect': case 'Radiation': if (enemyRobot != None) //score += 10000; bValid = false; break; case 'Burned': case 'Flamed': case 'Shot': if (enemyRobot != None) score += 0.5; break; case 'Sabot': if (enemyRobot != None) score -= 0.5; break; case 'EMP': case 'NanoVirus': if (enemyRobot != None) score -= 5.0; else if (enemyPlayer != None) score += 5.0; else //score += 10000; bValid = false; break; case 'Drowned': default: break; } // Special case for current weapon if ((curWeapon == Weapon) && (WeaponTimer < 10.0)) { // If we last changed weapons less than five seconds ago, // keep this weapon if (WeaponTimer < 5.0) score = -10; // If between five and ten seconds, use a sliding scale else score -= (10.0 - WeaponTimer)/5.0; } // Throw a little randomness into the computation... else { score += FRand()*0.1 - 0.05; if (score < 0) score = 0; } if (bValid) { // ugly if (bestWeapon == None) bWinner = true; else if (curFallbackLevel > fallbackLevel) bWinner = true; else if (curFallbackLevel < fallbackLevel) bWinner = false; else if (bestScore > score) bWinner = true; else bWinner = false; if (bWinner) { bestScore = score; bestWeapon = curWeapon; fallbackLevel = curFallbackLevel; } } } } inv = inv.Inventory; } // If we're changing weapons, reset the weapon timers if (Weapon != bestWeapon) { if (!bEnemySet) WeaponTimer = 10; // hack else WeaponTimer = 0; if (bestWeapon != None) if (bestWeapon.AITimeLimit > 0) SpecialTimer = bestWeapon.AITimeLimit; ReloadTimer = 0; } SetWeapon(bestWeapon); return false; } // ---------------------------------------------------------------------- // LoopBaseConvoAnim() // ---------------------------------------------------------------------- function LoopBaseConvoAnim() { // Special case for sitting if (bSitting) { if (!IsAnimating()) PlaySitting(); } // Special case for dancing else if (bDancing) { if (!IsAnimating()) PlayDancing(); } // Otherwise, just do the usual shit else Super.LoopBaseConvoAnim(); } // ---------------------------------------------------------------------- // BackOff() // ---------------------------------------------------------------------- function BackOff() { SetNextState(GetStateName(), 'ContinueFromDoor'); // MASSIVE hackage SetState('BackingOff'); } // ---------------------------------------------------------------------- // CheckDestLoc() // ---------------------------------------------------------------------- function CheckDestLoc(vector newDestLoc, optional bool bPathnode) { if (VSize(newDestLoc-LastDestLoc) <= 16) // too close DestAttempts++; else if (!IsPointInCylinder(self, newDestLoc)) DestAttempts++; else if (bPathnode && (VSize(newDestLoc-LastDestPoint) <= 16)) // too close DestAttempts++; else DestAttempts = 0; LastDestLoc = newDestLoc; if (bPathnode && (DestAttempts == 0)) LastDestPoint = newDestLoc; if (bEnableCheckDest && (DestAttempts >= 4)) BackOff(); } // ---------------------------------------------------------------------- // ResetDestLoc() // ---------------------------------------------------------------------- function ResetDestLoc() { DestAttempts = 0; LastDestLoc = vect(9999,9999,9999); // hack LastDestPoint = LastDestLoc; } // ---------------------------------------------------------------------- // EnableCheckDestLoc() // ---------------------------------------------------------------------- function EnableCheckDestLoc(bool bEnable) { // if (bEnableCheckDest && !bEnable) ResetDestLoc(); bEnableCheckDest = bEnable; } // ---------------------------------------------------------------------- // HandleTurn() // ---------------------------------------------------------------------- function bool HandleTurn(actor Other) { local bool bHandle; local bool bHackState; local DeusExDecoration dxDecoration; local ScriptedPawn scrPawn; // THIS ENTIRE SECTION IS A MASSIVE HACK TO GET AROUND PATHFINDING PROBLEMS // WHEN AN OBSTACLE COMPLETELY BLOCKS AN NPC'S PATH... bHandle = true; bHackState = false; if (bEnableCheckDest) { if (DestAttempts >= 2) { dxDecoration = DeusExDecoration(Other); scrPawn = ScriptedPawn(Other); if (dxDecoration != None) { if (!dxDecoration.bInvincible && !dxDecoration.bExplosive) { dxDecoration.HitPoints = 0; dxDecoration.TakeDamage(1, self, dxDecoration.Location, vect(0,0,0), 'Kick'); bHandle = false; } else if (DestAttempts >= 3) { bHackState = true; bHandle = false; } } else if (scrPawn != None) { if (DestAttempts >= 3) { if (scrPawn.GetStateName() != 'BackingOff') { bHackState = true; bHandle = false; } } } } if (bHackState) BackOff(); } return (bHandle); } // ---------------------------------------------------------------------- // Bump() // ---------------------------------------------------------------------- function Bump(actor Other) { local Rotator rot1, rot2; local int yaw; local ScriptedPawn avoidPawn; local DeusExPlayer dxPlayer; local bool bTurn; // Handle futzing and projectiles if (Other.Physics == PHYS_Falling) { if (DeusExProjectile(Other) != None) ReactToProjectiles(Other); else { dxPlayer = DeusExPlayer(Other.Instigator); if ((Other != dxPlayer) && (dxPlayer != None)) ReactToFutz(); } } // Have we walked into another (non-level) actor? bTurn = false; if ((Physics == PHYS_Walking) && (Acceleration != vect(0,0,0)) && bWalkAround && (Other != Level) && !Other.IsA('Mover')) if ((TurnDirection == TURNING_None) || (AvoidBumpTimer <= 0)) if (HandleTurn(Other)) bTurn = true; // Turn away from the actor if (bTurn) { // If we're not already turning, start if (TurnDirection == TURNING_None) { // Give ourselves a little extra time MoveTimer += 4.0; rot1 = Rotator(Other.Location-Location); // direction of object being bumped rot2 = Rotator(Acceleration); // direction we wish to go yaw = (rot2.Yaw - rot1.Yaw) & 65535; if (yaw > 32767) yaw -= 65536; // Depending on the angle we bump the actor, turn left or right if (yaw < 0) { TurnDirection = TURNING_Left; NextDirection = TURNING_Right; } else { TurnDirection = TURNING_Right; NextDirection = TURNING_Left; } bClearedObstacle = false; // Enable AlterDestination() bAdvancedTactics = true; } // Ignore multiple bumps in a row // BOOGER! Ignore same bump actor? if (AvoidBumpTimer <= 0) { AvoidBumpTimer = 0.2; ActorAvoiding = Other; bClearedObstacle = false; avoidPawn = ScriptedPawn(ActorAvoiding); // Avoid pairing off if (avoidPawn != None) { if ((avoidPawn.Acceleration != vect(0,0,0)) && (avoidPawn.Physics == PHYS_Walking) && (avoidPawn.TurnDirection != TURNING_None) && (avoidPawn.ActorAvoiding == self)) { if ((avoidPawn.TurnDirection == TURNING_Left) && (TurnDirection == TURNING_Right)) { TurnDirection = TURNING_Left; if (NextDirection != TURNING_None) NextDirection = TURNING_Right; } else if ((avoidPawn.TurnDirection == TURNING_Right) && (TurnDirection == TURNING_Left)) { TurnDirection = TURNING_Right; if (NextDirection != TURNING_None) NextDirection = TURNING_Left; } } } } } } // ---------------------------------------------------------------------- // HitWall() // ---------------------------------------------------------------------- function HitWall(vector HitLocation, Actor hitActor) { local ScriptedPawn avoidPawn; // We only care about HitWall as it pertains to level geometry if (hitActor != Level) return; // Are we walking? if ((Physics == PHYS_Walking) && (Acceleration != vect(0,0,0)) && bWalkAround && (AvoidWallTimer <= 0)) { // Are we turning? if (TurnDirection != TURNING_None) { AvoidWallTimer = 1.0; // About face TurnDirection = NextDirection; NextDirection = TURNING_None; bClearedObstacle = false; // Avoid pairing off avoidPawn = ScriptedPawn(ActorAvoiding); if (avoidPawn != None) { if ((avoidPawn.Acceleration != vect(0,0,0)) && (avoidPawn.Physics == PHYS_Walking) && (avoidPawn.TurnDirection != TURNING_None) && (avoidPawn.ActorAvoiding == self)) { if ((avoidPawn.TurnDirection == TURNING_Left) && (TurnDirection == TURNING_Right)) TurnDirection = TURNING_None; else if ((avoidPawn.TurnDirection == TURNING_Right) && (TurnDirection == TURNING_Left)) TurnDirection = TURNING_None; } } // Stopped turning? Shut down if (TurnDirection == TURNING_None) { ActorAvoiding = None; bAdvancedTactics = false; MoveTimer -= 4.0; ObstacleTimer = 0; } } } } // ---------------------------------------------------------------------- // AlterDestination() // ---------------------------------------------------------------------- function AlterDestination() { local Rotator dir; local int avoidYaw; local int destYaw; local int moveYaw; local int angle; local bool bPointInCylinder; local float dist1, dist2; local bool bAround; local vector tempVect; local ETurning oldTurnDir; oldTurnDir = TurnDirection; // Sanity check -- are we done walking around the actor? if (TurnDirection != TURNING_None) { if (!bWalkAround) TurnDirection = TURNING_None; else if (bClearedObstacle) TurnDirection = TURNING_None; else if (ActorAvoiding == None) TurnDirection = TURNING_None; else if (ActorAvoiding.bDeleteMe) TurnDirection = TURNING_None; else if (!IsPointInCylinder(ActorAvoiding, Location, CollisionRadius*2, CollisionHeight*2)) TurnDirection = TURNING_None; } // Are we still turning? if (TurnDirection != TURNING_None) { bAround = false; // Is our destination point inside the actor we're walking around? bPointInCylinder = IsPointInCylinder(ActorAvoiding, Destination, CollisionRadius-8, CollisionHeight-8); if (bPointInCylinder) { dist1 = VSize((Location - ActorAvoiding.Location)*vect(1,1,0)); dist2 = VSize((Location - Destination)*vect(1,1,0)); // Are we on the right side of the actor? if (dist1 > dist2) { // Just make a beeline, if possible tempVect = Destination - ActorAvoiding.Location; tempVect.Z = 0; tempVect = Normal(tempVect) * (ActorAvoiding.CollisionRadius + CollisionRadius); if (tempVect == vect(0,0,0)) Destination = Location; else { tempVect += ActorAvoiding.Location; tempVect.Z = Destination.Z; Destination = tempVect; } } else bAround = true; } else bAround = true; // We have a valid destination -- continue to walk around if (bAround) { // Determine the destination-self-obstacle angle dir = Rotator(ActorAvoiding.Location-Location); avoidYaw = dir.Yaw; dir = Rotator(Destination-Location); destYaw = dir.Yaw; if (TurnDirection == TURNING_Left) angle = (avoidYaw - destYaw) & 65535; else angle = (destYaw - avoidYaw) & 65535; if (angle < 0) angle += 65536; // If the angle is between 90 and 180 degrees, we've cleared the obstacle if (bPointInCylinder || (angle < 16384) || (angle > 32768)) // haven't cleared the actor yet { if (TurnDirection == TURNING_Left) moveYaw = avoidYaw - 16384; else moveYaw = avoidYaw + 16384; Destination = Location + Vector(rot(0,1,0)*moveYaw)*400; } else // cleared the actor -- move on TurnDirection = TURNING_None; } } if (TurnDirection == TURNING_None) { if (ObstacleTimer > 0) { TurnDirection = oldTurnDir; bClearedObstacle = true; } } else ObstacleTimer = 1.5; // Reset if done turning if (TurnDirection == TURNING_None) { NextDirection = TURNING_None; ActorAvoiding = None; bAdvancedTactics = false; ObstacleTimer = 0; bClearedObstacle = true; if (oldTurnDir != TURNING_None) MoveTimer -= 4.0; } } // ---------------------------------------------------------------------- // Frob() // ---------------------------------------------------------------------- function Frob(Actor Frobber, Inventory frobWith) { Super.Frob(Frobber, frobWith); // Check to see if the Frobber is the player. If so, then // check to see if we need to start a conversation. if (DeusExPlayer(Frobber) != None) { if (DeusExPlayer(Frobber).StartConversation(Self, IM_Frob)) { ConversationActor = Pawn(Frobber); return; } } } // ---------------------------------------------------------------------- // StopBlendAnims() // ---------------------------------------------------------------------- function StopBlendAnims() { AIAddViewRotation = rot(0, 0, 0); Super.StopBlendAnims(); PlayTurnHead(LOOK_Forward, 1.0, 1.0); } // ---------------------------------------------------------------------- // Falling() // ---------------------------------------------------------------------- singular function Falling() { if (bCanFly) { SetPhysics(PHYS_Flying); return; } // SetPhysics(PHYS_Falling); //note - done by default in physics if (health > 0) SetFall(); } // ---------------------------------------------------------------------- // SetFall() // ---------------------------------------------------------------------- function SetFall() { GotoState('FallingState'); } // ---------------------------------------------------------------------- // LongFall() // ---------------------------------------------------------------------- function LongFall() { SetFall(); GotoState('FallingState', 'LongFall'); } // ---------------------------------------------------------------------- // HearNoise() // ---------------------------------------------------------------------- function HearNoise(float Loudness, Actor NoiseMaker) { // Do nothing } // ---------------------------------------------------------------------- // SeePlayer() // ---------------------------------------------------------------------- function SeePlayer(Actor SeenPlayer) { // Do nothing } // ---------------------------------------------------------------------- // Trigger() // ---------------------------------------------------------------------- function Trigger( actor Other, pawn EventInstigator ) { // Do nothing } // ---------------------------------------------------------------------- // Reloading() // ---------------------------------------------------------------------- function Reloading(DeusExWeapon reloadWeapon, float reloadTime) { if (reloadWeapon == Weapon) ReloadTimer = reloadTime; } // ---------------------------------------------------------------------- // DoneReloading() // ---------------------------------------------------------------------- function DoneReloading(DeusExWeapon reloadWeapon) { if (reloadWeapon == Weapon) ReloadTimer = 0; } // ---------------------------------------------------------------------- // IsWeaponReloading() // ---------------------------------------------------------------------- function bool IsWeaponReloading() { return (ReloadTimer >= 0.3); } // ---------------------------------------------------------------------- // HandToHandAttack() // ---------------------------------------------------------------------- function HandToHandAttack() { local DeusExWeapon dxWeapon; dxWeapon = DeusExWeapon(Weapon); if (dxWeapon != None) dxWeapon.OwnerHandToHandAttack(); } // ---------------------------------------------------------------------- // Killed() // ---------------------------------------------------------------------- function Killed(pawn Killer, pawn Other, name damageType) { if ((Enemy == Other) && (Other != None) && !Other.bIsPlayer) Enemy = None; } // ---------------------------------------------------------------------- // Died() // ---------------------------------------------------------------------- function Died(pawn Killer, name damageType, vector HitLocation) { local DeusExPlayer player; local name flagName; // Set a flag when NPCs die so we can possibly check it later player = DeusExPlayer(GetPlayerPawn()); ExtinguishFire(); // set the instigator to be the killer Instigator = Killer; if (player != None) { // Abort any conversation we may have been having with the NPC if (bInConversation) player.AbortConversation(); // Abort any barks we may have been playing if (player.BarkManager != None) player.BarkManager.ScriptedPawnDied(Self); } Super.Died(Killer, damageType, HitLocation); // bStunned is set here if (player != None) { if (bImportant) { flagName = player.rootWindow.StringToName(BindName$"_Dead"); player.flagBase.SetBool(flagName, True); // make sure the flag never expires player.flagBase.SetExpiration(flagName, FLAG_Bool, 0); if (bStunned) { flagName = player.rootWindow.StringToName(BindName$"_Unconscious"); player.flagBase.SetBool(flagName, True); // make sure the flag never expires player.flagBase.SetExpiration(flagName, FLAG_Bool, 0); } } } } // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // STATES // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // state StartUp // // Initial state // ---------------------------------------------------------------------- auto state StartUp { function BeginState() { bInterruptState = true; bCanConverse = false; SetMovementPhysics(); if (Physics == PHYS_Walking) SetPhysics(PHYS_Falling); bStasis = False; SetDistress(false); BlockReactions(); ResetDestLoc(); } function EndState() { bCanConverse = true; bStasis = True; ResetReactions(); } function Tick(float deltaSeconds) { Global.Tick(deltaSeconds); if (LastRendered() <= 1.0) { PlayWaiting(); InitializePawn(); FollowOrders(); } } Begin: InitializePawn(); Sleep(FRand()+0.2); WaitForLanding(); Start: FollowOrders(); } // ---------------------------------------------------------------------- // state Paralyzed // // Do nothing -- ignore all // (this state lets ViewModel work correctly) // ---------------------------------------------------------------------- state Paralyzed { ignores bump, frob, reacttoinjury; function BeginState() { StandUp(); BlockReactions(true); bCanConverse = False; SeekPawn = None; EnableCheckDestLoc(false); } function EndState() { ResetReactions(); bCanConverse = True; } Begin: Acceleration=vect(0,0,0); PlayAnimPivot('Still'); } // ---------------------------------------------------------------------- // state Idle // // Do nothing // ---------------------------------------------------------------------- state Idle { ignores bump, frob, reacttoinjury; function BeginState() { StandUp(); BlockReactions(true); bCanConverse = False; SeekPawn = None; EnableCheckDestLoc(false); } function EndState() { ResetReactions(); bCanConverse = True; } Begin: Acceleration=vect(0,0,0); DesiredRotation=Rotation; PlayAnimPivot('Still'); Idle: } // ---------------------------------------------------------------------- // state Conversation // // Just sit here until the conversation is over // ---------------------------------------------------------------------- state Conversation { function Tick(float deltaTime) { Global.Tick(deltaTime); LipSynch(deltaTime); // Keep turning towards the person we're speaking to if (ConversationActor != None) { if (bSitting) { if (SeatActor != None) LookAtActor(ConversationActor, true, true, true, 0, 0.5, SeatActor.Rotation.Yaw+49152, 5461); else LookAtActor(ConversationActor, false, true, true, 0, 0.5); } else LookAtActor(ConversationActor, true, true, true, 0, 0.5); } } function LoopHeadConvoAnim() { } function SetOrders(Name orderName, optional Name newOrderTag, optional bool bImmediate) { local DeusExPlayer dxPlayer; dxPlayer = DeusExPlayer(GetPlayerPawn()); if (dxPlayer != None) if (dxPlayer.ConPlay != None) if (dxPlayer.ConPlay.GetForcePlay()) { Global.SetOrders(orderName, newOrderTag, bImmediate); return; } ConvOrders = orderName; ConvOrderTag = newOrderTag; } function FollowOrders(optional bool bDefer) { local name tempConvOrders, tempConvOrderTag; // hack tempConvOrders = ConvOrders; tempConvOrderTag = ConvOrderTag; ResetConvOrders(); // must do this before calling SetOrders(), or recursion will result if (tempConvOrders != '') Global.SetOrders(tempConvOrders, tempConvOrderTag, true); else Global.FollowOrders(bDefer); } function BeginState() { local DeusExPlayer dxPlayer; local bool bBlock; ResetConvOrders(); EnableCheckDestLoc(false); bBlock = True; dxPlayer = DeusExPlayer(GetPlayerPawn()); if (dxPlayer != None) if (dxPlayer.ConPlay != None) if (dxPlayer.ConPlay.CanInterrupt()) bBlock = False; bInterruptState = True; if (bBlock) { bCanConverse = False; MakePawnIgnored(true); BlockReactions(true); } else { bCanConverse = True; MakePawnIgnored(true); BlockReactions(false); } // Check if the current state is "WaitingFor", "RunningTo" or "GoingTo", in which case // we want the orders to be 'Standing' after the conversation is over. UNLESS the // ScriptedPawn was going somewhere else (OrderTag != '') if (((Orders == 'WaitingFor') || (Orders == 'RunningTo') || (Orders == 'GoingTo')) && (OrderTag == '')) SetOrders('Standing'); bConversationEndedNormally = False; bInConversation = True; bStasis = False; SetDistress(false); SeekPawn = None; } function EndState() { local DeusExPlayer player; local bool bForcePlay; bForcePlay = false; player = DeusExPlayer(GetPlayerPawn()); if (player != None) if (player.conPlay != None) bForcePlay = player.conPlay.GetForcePlay(); bConvEndState = true; if (!bForcePlay && (bConversationEndedNormally != True)) player.AbortConversation(); bConvEndState = false; ResetConvOrders(); StopBlendAnims(); bInterruptState = true; bCanConverse = True; MakePawnIgnored(false); ResetReactions(); bStasis = True; ConversationActor = None; } Begin: Acceleration = vect(0,0,0); DesiredRotation.Pitch = 0; if (!bSitting && !bDancing) PlayWaiting(); // we are now idle } // ---------------------------------------------------------------------- // state FirstPersonConversation // // Just sit here until the conversation is over // ---------------------------------------------------------------------- state FirstPersonConversation { function Tick(float deltaTime) { Global.Tick(deltaTime); LipSynch(deltaTime); // Keep turning towards the person we're speaking to if (ConversationActor != None) { if (bSitting) { if (SeatActor != None) LookAtActor(ConversationActor, true, true, true, 0, 1.0, SeatActor.Rotation.Yaw+49152, 5461); else LookAtActor(ConversationActor, false, true, true, 0, 1.0); } else LookAtActor(ConversationActor, true, true, true, 0, 1.0); } } function LoopHeadConvoAnim() { } function SetOrders(Name orderName, optional Name newOrderTag, optional bool bImmediate) { ConvOrders = orderName; ConvOrderTag = newOrderTag; } function FollowOrders(optional bool bDefer) { local name tempConvOrders, tempConvOrderTag; // hack tempConvOrders = ConvOrders; tempConvOrderTag = ConvOrderTag; ResetConvOrders(); // must do this before calling SetOrders(), or recursion will result if (tempConvOrders != '') Global.SetOrders(tempConvOrders, tempConvOrderTag, true); else Global.FollowOrders(bDefer); } function BeginState() { local DeusExPlayer dxPlayer; local bool bBlock; ResetConvOrders(); EnableCheckDestLoc(false); dxPlayer = DeusExPlayer(GetPlayerPawn()); /* bBlock = True; if (dxPlayer != None) if (dxPlayer.ConPlay != None) if (dxPlayer.ConPlay.CanInterrupt()) bBlock = False; */ // 1st-person conversations will no longer block; // left old code in here in case people change their minds :) bBlock = false; bInterruptState = True; if (bBlock) { bCanConverse = False; MakePawnIgnored(true); BlockReactions(true); } else { bCanConverse = True; MakePawnIgnored(false); if ((dxPlayer != None) && (dxPlayer.conPlay != None) && dxPlayer.conPlay.con.IsSpeakingActor(dxPlayer)) SetReactions(false, false, false, false, true, false, false, true, false, false, true, true); else ResetReactions(); } bConversationEndedNormally = False; bInConversation = True; bStasis = False; SetDistress(false); SeekPawn = None; } function EndState() { local DeusExPlayer player; bConvEndState = true; if (bConversationEndedNormally != True) { player = DeusExPlayer(GetPlayerPawn()); player.AbortConversation(); } bConvEndState = false; ResetConvOrders(); StopBlendAnims(); bInterruptState = true; bCanConverse = True; MakePawnIgnored(false); ResetReactions(); bStasis = True; ConversationActor = None; } Begin: Acceleration = vect(0,0,0); DesiredRotation.Pitch = 0; if (!bSitting && !bDancing) PlayWaiting(); // we are now idle } // ---------------------------------------------------------------------- // EnterConversationState() // ---------------------------------------------------------------------- function EnterConversationState(bool bFirstPerson, optional bool bAvoidState) { // First check to see if we're already in a conversation state, // in which case we'll abort immediately if ((GetStateName() == 'Conversation') || (GetStateName() == 'FirstPersonConversation')) return; SetNextState(GetStateName(), 'Begin'); // If bAvoidState is set, then we don't want to jump into the conversaton state // for the ScriptedPawn, because bad things might happen otherwise. if (!bAvoidState) { if (bFirstPerson) GotoState('FirstPersonConversation'); else GotoState('Conversation'); } } // ---------------------------------------------------------------------- // state Standing // // Just kinda stand there and do nothing. // (similar to Wandering, except the pawn doesn't actually move) // ---------------------------------------------------------------------- state Standing { ignores EnemyNotVisible; function SetFall() { StartFalling('Standing', 'ContinueStand'); } function AnimEnd() { PlayWaiting(); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function Tick(float deltaSeconds) { animTimer[1] += deltaSeconds; Global.Tick(deltaSeconds); } function BeginState() { StandUp(); SetEnemy(None, EnemyLastSeen, true); Disable('AnimEnd'); bCanJump = false; bStasis = False; SetupWeapon(false); SetDistress(false); SeekPawn = None; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); bAcceptBump = True; if (JumpZ > 0) bCanJump = true; bStasis = True; StopBlendAnims(); } Begin: WaitForLanding(); if (!bUseHome) Goto('StartStand'); MoveToBase: if (!IsPointInCylinder(self, HomeLoc, 16-CollisionRadius)) { EnableCheckDestLoc(true); while (true) { if (PointReachable(HomeLoc)) { if (ShouldPlayWalk(HomeLoc)) PlayWalking(); MoveTo(HomeLoc, GetWalkingSpeed()); CheckDestLoc(HomeLoc); break; } else { MoveTarget = FindPathTo(HomeLoc); if (MoveTarget != None) { if (ShouldPlayWalk(MoveTarget.Location)) PlayWalking(); MoveToward(MoveTarget, GetWalkingSpeed()); CheckDestLoc(MoveTarget.Location, true); } else break; } } EnableCheckDestLoc(false); } TurnTo(Location+HomeRot); StartStand: Acceleration=vect(0,0,0); Goto('Stand'); ContinueFromDoor: Goto('MoveToBase'); Stand: ContinueStand: // nil bStasis = True; PlayWaiting(); if (!bPlayIdle) Goto('DoNothing'); Sleep(FRand()*14+8); Fidget: if (FRand() < 0.5) { PlayIdle(); FinishAnim(); } else { if (FRand() > 0.5) { PlayTurnHead(LOOK_Up, 1.0, 1.0); Sleep(2.0); PlayTurnHead(LOOK_Forward, 1.0, 1.0); Sleep(0.5); } else if (FRand() > 0.5) { PlayTurnHead(LOOK_Left, 1.0, 1.0); Sleep(1.5); PlayTurnHead(LOOK_Forward, 1.0, 1.0); Sleep(0.9); PlayTurnHead(LOOK_Right, 1.0, 1.0); Sleep(1.2); PlayTurnHead(LOOK_Forward, 1.0, 1.0); Sleep(0.5); } else { PlayTurnHead(LOOK_Right, 1.0, 1.0); Sleep(1.5); PlayTurnHead(LOOK_Forward, 1.0, 1.0); Sleep(0.9); PlayTurnHead(LOOK_Left, 1.0, 1.0); Sleep(1.2); PlayTurnHead(LOOK_Forward, 1.0, 1.0); Sleep(0.5); } } if (FRand() < 0.3) PlayIdleSound(); Goto('Stand'); DoNothing: // nil } // ---------------------------------------------------------------------- // state Dancing // // Dance in place. // (Most of this code was ripped from Standing) // ---------------------------------------------------------------------- state Dancing { ignores EnemyNotVisible; function SetFall() { StartFalling('Dancing', 'ContinueDance'); } function AnimEnd() { PlayDancing(); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function BeginState() { if (bSitting && !bDancing) StandUp(); SetEnemy(None, EnemyLastSeen, true); Disable('AnimEnd'); bCanJump = false; bStasis = False; SetupWeapon(false); SetDistress(false); SeekPawn = None; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); bAcceptBump = True; if (JumpZ > 0) bCanJump = true; bStasis = True; StopBlendAnims(); } Begin: WaitForLanding(); if (bDancing) { if (bUseHome) TurnTo(Location+HomeRot); Goto('StartDance'); } if (!bUseHome) Goto('StartDance'); MoveToBase: if (!IsPointInCylinder(self, HomeLoc, 16-CollisionRadius)) { EnableCheckDestLoc(true); while (true) { if (PointReachable(HomeLoc)) { if (ShouldPlayWalk(HomeLoc)) PlayWalking(); MoveTo(HomeLoc, GetWalkingSpeed()); CheckDestLoc(HomeLoc); break; } else { MoveTarget = FindPathTo(HomeLoc); if (MoveTarget != None) { if (ShouldPlayWalk(MoveTarget.Location)) PlayWalking(); MoveToward(MoveTarget, GetWalkingSpeed()); CheckDestLoc(MoveTarget.Location, true); } else break; } } EnableCheckDestLoc(false); } TurnTo(Location+HomeRot); StartDance: Acceleration=vect(0,0,0); Goto('Dance'); ContinueFromDoor: Goto('MoveToBase'); Dance: ContinueDance: // nil bDancing = True; PlayDancing(); bStasis = True; if (!bHokeyPokey) Goto('DoNothing'); Spin: Sleep(FRand()*5+5); useRot = DesiredRotation; if (FRand() > 0.5) { TurnTo(Location+1000*vector(useRot+rot(0,16384,0))); TurnTo(Location+1000*vector(useRot+rot(0,32768,0))); TurnTo(Location+1000*vector(useRot+rot(0,49152,0))); } else { TurnTo(Location+1000*vector(useRot+rot(0,49152,0))); TurnTo(Location+1000*vector(useRot+rot(0,32768,0))); TurnTo(Location+1000*vector(useRot+rot(0,16384,0))); } TurnTo(Location+1000*vector(useRot)); Goto('Spin'); DoNothing: // nil } // ---------------------------------------------------------------------- // state Sitting // // Just kinda sit there and do nothing. // (doubles as a shitting state) // ---------------------------------------------------------------------- state Sitting { ignores EnemyNotVisible; function SetFall() { StartFalling('Sitting', 'ContinueSit'); } function AnimEnd() { PlayWaiting(); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; if (!bAcceptBump) NextDirection = TURNING_None; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function bool HandleTurn(Actor Other) { if (Other == SeatActor) return true; else return Global.HandleTurn(Other); } function Bump(actor bumper) { // If we hit our chair, move to the right place if ((bumper == SeatActor) && bAcceptBump) { bAcceptBump = false; GotoState('Sitting', 'CircleToFront'); } // Handle conversations, if need be else Global.Bump(bumper); } function Tick(float deltaSeconds) { local vector endPos; local vector newPos; local float delta; Global.Tick(deltaSeconds); if (bSitInterpolation && (SeatActor != None)) { endPos = SitPosition(SeatActor, SeatSlot); if ((deltaSeconds < remainingSitTime) && (remainingSitTime > 0)) { delta = deltaSeconds/remainingSitTime; newPos = (endPos-Location)*delta + Location; remainingSitTime -= deltaSeconds; } else { remainingSitTime = 0; bSitInterpolation = false; newPos = endPos; Acceleration = vect(0,0,0); Velocity = vect(0,0,0); SetBase(SeatActor); bSitting = true; } SetLocation(newPos); DesiredRotation = SeatActor.Rotation+Rot(0, -16384, 0); } } function Vector SitPosition(Seat seatActor, int slot) { local float newAssHeight; newAssHeight = GetDefaultCollisionHeight() + BaseAssHeight; newAssHeight = -(CollisionHeight - newAssHeight); return ((seatActor.sitPoint[slot]>>seatActor.Rotation)+seatActor.Location+(vect(0,0,-1)*newAssHeight)); } function vector GetDestinationPosition(Seat seatActor, optional float extraDist) { local Rotator seatRot; local Vector destPos; if (seatActor == None) return (Location); seatRot = seatActor.Rotation + Rot(0, -16384, 0); seatRot.Pitch = 0; destPos = seatActor.Location; destPos += vect(0,0,1)*(CollisionHeight-seatActor.CollisionHeight); destPos += Vector(seatRot)*(seatActor.CollisionRadius+CollisionRadius+extraDist); return (destPos); } function bool IsIntersectingSeat() { local bool bIntersect; local vector testVector; bIntersect = false; if (SeatActor != None) bIntersect = IsOverlapping(SeatActor); return (bIntersect); } function int FindBestSlot(Seat seatActor, out float slotDist) { local int bestSlot; local float dist; local float bestDist; local int i; bestSlot = -1; bestDist = 100; if (!seatActor.Region.Zone.bWaterZone) { for (i=0; i<seatActor.numSitPoints; i++) { if (seatActor.sittingActor[i] == None) { dist = VSize(SitPosition(seatActor, i) - Location); if ((bestSlot < 0) || (bestDist > dist)) { bestDist = dist; bestSlot = i; } } } } slotDist = bestDist; return (bestSlot); } function FindBestSeat() { local Seat curSeat; local Seat bestSeat; local float curDist; local float bestDist; local int curSlot; local int bestSlot; local bool bTry; if (bUseFirstSeatOnly && bSeatHackUsed) { bestSeat = SeatHack; // use the seat hack bestSlot = -1; if (!IsSeatValid(bestSeat)) bestSeat = None; else { if (GetNextWaypoint(bestSeat) == None) bestSeat = None; else { bestSlot = FindBestSlot(bestSeat, curDist); if (bestSlot < 0) bestSeat = None; } } } else { bestSeat = Seat(OrderActor); // try the ordered seat first if (bestSeat != None) { if (!IsSeatValid(OrderActor)) bestSeat = None; else { if (GetNextWaypoint(bestSeat) == None) bestSeat = None; else { bestSlot = FindBestSlot(bestSeat, curDist); if (bestSlot < 0) bestSeat = None; } } } if (bestSeat == None) { bestDist = 10001; bestSlot = -1; foreach RadiusActors(Class'Seat', curSeat, 10000) { if (IsSeatValid(curSeat)) { curSlot = FindBestSlot(curSeat, curDist); if (curSlot >= 0) { if (bestDist > curDist) { if (GetNextWaypoint(curSeat) != None) { bestDist = curDist; bestSeat = curSeat; bestSlot = curSlot; } } } } } } } if (bestSeat != None) { bestSeat.sittingActor[bestSlot] = self; SeatLocation = bestSeat.Location; bSeatLocationValid = true; } else bSeatLocationValid = false; if (bUseFirstSeatOnly && !bSeatHackUsed) { SeatHack = bestSeat; bSeatHackUsed = true; } SeatActor = bestSeat; SeatSlot = bestSlot; } function FollowSeatFallbackOrders() { FindBestSeat(); if (IsSeatValid(SeatActor)) GotoState('Sitting', 'Begin'); else GotoState('Wandering'); } function BeginState() { SetEnemy(None, EnemyLastSeen, true); Disable('AnimEnd'); bCanJump = false; bAcceptBump = True; if (SeatActor == None) FindBestSeat(); bSitInterpolation = false; bStasis = False; SetupWeapon(false); SetDistress(false); SeekPawn = None; EnableCheckDestLoc(true); } function EndState() { EnableCheckDestLoc(false); if (!bSitting) StandUp(); bAcceptBump = True; if (JumpZ > 0) bCanJump = true; bSitInterpolation = false; bStasis = True; } Begin: WaitForLanding(); if (!IsSeatValid(SeatActor)) FollowSeatFallbackOrders(); if (!bSitting) WaitForLanding(); else { TurnTo(Vector(SeatActor.Rotation+Rot(0, -16384, 0))*100+Location); Goto('ContinueSitting'); } MoveToSeat: if (IsIntersectingSeat()) Goto('MoveToPosition'); bAcceptBump = true; while (true) { if (!IsSeatValid(SeatActor)) FollowSeatFallbackOrders(); destLoc = GetDestinationPosition(SeatActor); if (PointReachable(destLoc)) { if (ShouldPlayWalk(destLoc)) PlayWalking(); MoveTo(destLoc, GetWalkingSpeed()); CheckDestLoc(destLoc); if (IsPointInCylinder(self, GetDestinationPosition(SeatActor), 16, 16)) { bAcceptBump = false; Goto('MoveToPosition'); break; } } else { MoveTarget = GetNextWaypoint(SeatActor); if (MoveTarget != None) { if (ShouldPlayWalk(MoveTarget.Location)) PlayWalking(); MoveToward(MoveTarget, GetWalkingSpeed()); CheckDestLoc(MoveTarget.Location, true); } else break; } } CircleToFront: bAcceptBump = false; if (!IsSeatValid(SeatActor)) FollowSeatFallbackOrders(); if (ShouldPlayWalk(GetDestinationPosition(SeatActor, 16))) PlayWalking(); MoveTo(GetDestinationPosition(SeatActor, 16), GetWalkingSpeed()); MoveToPosition: if (!IsSeatValid(SeatActor)) FollowSeatFallbackOrders(); bSitting = true; EnableCollision(false); Acceleration=vect(0,0,0); Sit: Acceleration=vect(0,0,0); Velocity=vect(0,0,0); if (!IsSeatValid(SeatActor)) FollowSeatFallbackOrders(); remainingSitTime = 0.8; PlaySittingDown(); SetBasedPawnSize(CollisionRadius, GetSitHeight()); SetPhysics(PHYS_Flying); StopStanding(); bSitInterpolation = true; while (bSitInterpolation) Sleep(0); FinishAnim(); Goto('ContinueSitting'); ContinueFromDoor: Goto('MoveToSeat'); ContinueSitting: if (!IsSeatValid(SeatActor)) FollowSeatFallbackOrders(); SetBasedPawnSize(CollisionRadius, GetSitHeight()); SetCollision(Default.bCollideActors, Default.bBlockActors, Default.bBlockPlayers); PlaySitting(); bStasis = True; // nil } // ---------------------------------------------------------------------- // state HandlingEnemy // // Fight-or-flight state // ---------------------------------------------------------------------- state HandlingEnemy { function BeginState() { if (Enemy == None) GotoState('Seeking'); else if (RaiseAlarm == RAISEALARM_BeforeAttacking) GotoState('Alerting'); else GotoState('Attacking'); } Begin: } // ---------------------------------------------------------------------- // state Wandering // // Meander from place to place, occasionally gazing into the middle // distance. // ---------------------------------------------------------------------- state Wandering { ignores EnemyNotVisible; function SetFall() { StartFalling('Wandering', 'ContinueWander'); } function Bump(actor bumper) { if (bAcceptBump) { // If we get bumped by another actor while we wait, start wandering again bAcceptBump = False; Disable('AnimEnd'); GotoState('Wandering', 'Wander'); } // Handle conversations, if need be Global.Bump(bumper); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function bool GoHome() { if (bUseHome && !IsNearHome(Location)) { destLoc = HomeLoc; destPoint = None; if (PointReachable(destLoc)) return true; else { MoveTarget = FindPathTo(destLoc); if (MoveTarget != None) return true; else return false; } } else return false; } function PickDestination() { local WanderCandidates candidates[5]; local int candidateCount; local int maxCandidates; local int maxLastPoints; local WanderPoint curPoint; local Actor wayPoint; local int i; local int openSlot; local float maxDist; local float dist; local float angle; local float magnitude; local int iterations; local bool bSuccess; local Rotator rot; maxCandidates = 4; // must be <= size of candidates[] array maxLastPoints = 2; // must be <= size of lastPoints[] array for (i=0; i<maxCandidates; i++) candidates[i].dist = 100000; candidateCount = 0; // A certain percentage of the time, we want to angle off to a random direction... if ((RandomWandering < 1) && (FRand() > RandomWandering)) { // Fill the candidate table foreach RadiusActors(Class'WanderPoint', curPoint, 3000*wanderlust+1000) // 1000-4000 { // Make sure we haven't been here recently for (i=0; i<maxLastPoints; i++) { if (lastPoints[i] == curPoint) break; } if (i >= maxLastPoints) { // Can we get there from here? wayPoint = GetNextWaypoint(curPoint); if ((wayPoint != None) && !IsNearHome(curPoint.Location)) wayPoint = None; // Yep if (wayPoint != None) { // Find an empty slot for this candidate openSlot = -1; dist = VSize(curPoint.location - location); maxDist = dist; // This candidate will only replace more distant candidates... for (i=0; i<maxCandidates; i++) { if (maxDist < candidates[i].dist) { maxDist = candidates[i].dist; openSlot = i; } } // Put the candidate in the (unsorted) list if (openSlot >= 0) { candidates[openSlot].point = curPoint; candidates[openSlot].waypoint = wayPoint; candidates[openSlot].dist = dist; if (candidateCount < maxCandidates) candidateCount++; } } } } } // Shift our list of recently visited points for (i=maxLastPoints-1; i>0; i--) lastPoints[i] = lastPoints[i-1]; lastPoints[0] = None; // Do we have a list of candidates? if (candidateCount > 0) { // Pick a candidate at random i = Rand(candidateCount); curPoint = candidates[i].point; wayPoint = candidates[i].waypoint; lastPoints[0] = curPoint; MoveTarget = wayPoint; destPoint = curPoint; } // No candidates -- find a random place to go else { MoveTarget = None; destPoint = None; iterations = 6; // try up to 6 different directions while (iterations > 0) { // How far will we go? magnitude = (wanderlust*400+200) * (FRand()*0.2+0.9); // 200-600, +/-10% // Choose our destination, based on whether we have a home base if (!bUseHome) bSuccess = AIPickRandomDestination(100, magnitude, 0, 0, 0, 0, 1, FRand()*0.4+0.35, destLoc); else { if (magnitude > HomeExtent) magnitude = HomeExtent*(FRand()*0.2+0.9); rot = Rotator(HomeLoc-Location); bSuccess = AIPickRandomDestination(50, magnitude, rot.Yaw, 0.25, rot.Pitch, 0.25, 1, FRand()*0.4+0.35, destLoc); } // Success? Break out of the iteration loop if (bSuccess) if (IsNearHome(destLoc)) break; // We failed -- try again iterations--; } // If we got a destination, go there if (iterations <= 0) destLoc = Location; } } function AnimEnd() { PlayWaiting(); } function BeginState() { StandUp(); SetEnemy(None, EnemyLastSeen, true); Disable('AnimEnd'); bCanJump = false; SetupWeapon(false); SetDistress(false); SeekPawn = None; EnableCheckDestLoc(false); } function EndState() { local int i; bAcceptBump = True; EnableCheckDestLoc(false); // Clear out our list of last visited points for (i=0; i<ArrayCount(lastPoints); i++) lastPoints[i] = None; if (JumpZ > 0) bCanJump = true; } Begin: destPoint = None; GoHome: bAcceptBump = false; WaitForLanding(); if (!GoHome()) Goto('WanderInternal'); MoveHome: EnableCheckDestLoc(true); while (true) { if (PointReachable(destLoc)) { if (ShouldPlayWalk(destLoc)) PlayWalking(); MoveTo(destLoc, GetWalkingSpeed()); CheckDestLoc(destLoc); break; } else { MoveTarget = FindPathTo(destLoc); if (MoveTarget != None) { if (ShouldPlayWalk(MoveTarget.Location)) PlayWalking(); MoveToward(MoveTarget, GetWalkingSpeed()); CheckDestLoc(MoveTarget.Location, true); } else break; } } EnableCheckDestLoc(false); Goto('Pausing'); Wander: WaitForLanding(); WanderInternal: PickDestination(); Moving: // Move from pathnode to pathnode until we get where we're going // (ooooold code -- no longer used) if (destPoint != None) { if (ShouldPlayWalk(MoveTarget.Location)) PlayWalking(); MoveToward(MoveTarget, GetWalkingSpeed()); while ((MoveTarget != None) && (MoveTarget != destPoint)) { MoveTarget = FindPathToward(destPoint); if (MoveTarget != None) { if (ShouldPlayWalk(MoveTarget.Location)) PlayWalking(); MoveToward(MoveTarget, GetWalkingSpeed()); } } } else if (destLoc != Location) { if (ShouldPlayWalk(destLoc)) PlayWalking(); MoveTo(destLoc, GetWalkingSpeed()); } else Sleep(0.5); Pausing: Acceleration = vect(0, 0, 0); // Turn in the direction dictated by the WanderPoint, if there is one sleepTime = 6.0; if (WanderPoint(destPoint) != None) { if (WanderPoint(destPoint).gazeItem != None) { TurnToward(WanderPoint(destPoint).gazeItem); sleepTime = WanderPoint(destPoint).gazeDuration; } else if (WanderPoint(destPoint).gazeDirection != vect(0, 0, 0)) TurnTo(Location + WanderPoint(destPoint).gazeDirection); } Enable('AnimEnd'); TweenToWaiting(0.2); bAcceptBump = True; PlayScanningSound(); sleepTime *= (-0.9*restlessness) + 1; Sleep(sleepTime); Disable('AnimEnd'); bAcceptBump = False; FinishAnim(); Goto('Wander'); ContinueWander: ContinueFromDoor: FinishAnim(); PlayWalking(); Goto('Wander'); } // ---------------------------------------------------------------------- // state Leaving // // Just like Patrolling, but make the pawn transient. // ---------------------------------------------------------------------- State Leaving { function BeginState() { bTransient = True; // this pawn will be destroyed when it gets out of range bDisappear = True; GotoState('Patrolling'); } Begin: // shouldn't ever reach this point } // ---------------------------------------------------------------------- // state Patrolling // // Move from point to point in a predescribed pattern. // ---------------------------------------------------------------------- State Patrolling { function SetFall() { StartFalling('Patrolling', 'ContinuePatrol'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function AnimEnd() { PlayWaiting(); } function PatrolPoint PickStartPoint() { local NavigationPoint nav; local PatrolPoint curNav; local float curDist; local PatrolPoint closestNav; local float closestDist; nav = Level.NavigationPointList; while (nav != None) { nav.visitedWeight = 0; nav = nav.nextNavigationPoint; } closestNav = None; closestDist = 100000; nav = Level.NavigationPointList; while (nav != None) { curNav = PatrolPoint(nav); if ((curNav != None) && (curNav.Tag == OrderTag)) { while (curNav != None) { if (curNav.visitedWeight != 0) // been here before break; curDist = VSize(Location - curNav.Location); if ((closestNav == None) || (closestDist > curDist)) { closestNav = curNav; closestDist = curDist; } curNav.visitedWeight = 1; curNav = curNav.NextPatrolPoint; } } nav = nav.nextNavigationPoint; } return (closestNav); } function PickDestination() { if (PatrolPoint(destPoint) != None) destPoint = PatrolPoint(destPoint).NextPatrolPoint; else destPoint = PickStartPoint(); if (destPoint == None) // can't go anywhere... GotoState('Standing'); } function BeginState() { StandUp(); SetEnemy(None, EnemyLastSeen, true); Disable('AnimEnd'); SetupWeapon(false); SetDistress(false); bStasis = false; SeekPawn = None; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); Enable('AnimEnd'); bStasis = true; } Begin: destPoint = None; Patrol: //Disable('Bump'); WaitForLanding(); PickDestination(); Moving: // Move from pathnode to pathnode until we get where we're going if (destPoint != None) { if (!IsPointInCylinder(self, destPoint.Location, 16-CollisionRadius)) { EnableCheckDestLoc(true); MoveTarget = FindPathToward(destPoint); while (MoveTarget != None) { if (ShouldPlayWalk(MoveTarget.Location)) PlayWalking(); MoveToward(MoveTarget, GetWalkingSpeed()); CheckDestLoc(MoveTarget.Location, true); if (MoveTarget == destPoint) break; MoveTarget = FindPathToward(destPoint); } EnableCheckDestLoc(false); } } else Goto('Patrol'); Pausing: if (!bAlwaysPatrol) bStasis = true; Acceleration = vect(0, 0, 0); // Turn in the direction dictated by the WanderPoint, or a random direction if (PatrolPoint(destPoint) != None) { if ((PatrolPoint(destPoint).pausetime > 0) || (PatrolPoint(destPoint).NextPatrolPoint == None)) { if (ShouldPlayTurn(Location + PatrolPoint(destPoint).lookdir)) PlayTurning(); TurnTo(Location + PatrolPoint(destPoint).lookdir); Enable('AnimEnd'); TweenToWaiting(0.2); PlayScanningSound(); //Enable('Bump'); sleepTime = PatrolPoint(destPoint).pausetime * ((-0.9*restlessness) + 1); Sleep(sleepTime); Disable('AnimEnd'); //Disable('Bump'); FinishAnim(); } } Goto('Patrol'); ContinuePatrol: ContinueFromDoor: FinishAnim(); PlayWalking(); Goto('Moving'); } // ---------------------------------------------------------------------- // state Seeking // // Look for enemies in the area // ---------------------------------------------------------------------- State Seeking { function SetFall() { StartFalling('Seeking', 'ContinueSeek'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function bool GetNextLocation(out vector nextLoc) { local float dist; local rotator rotation; local bool bDone; local float seekDistance; local Actor hitActor; local vector HitLocation, HitNormal; local vector diffVect; local bool bLOS; if (bSeekLocation) { if (SeekType == SEEKTYPE_Guess) seekDistance = (200+FClamp(GroundSpeed*EnemyLastSeen*0.5, 0, 1000)); else seekDistance = 300; } else seekDistance = 60; dist = VSize(Location-destLoc); bDone = false; bLOS = false; if (dist < seekDistance) { bLOS = true; foreach TraceVisibleActors(Class'Actor', hitActor, hitLocation, hitNormal, destLoc, Location+vect(0,0,1)*BaseEyeHeight) { if (hitActor != self) { if (hitActor == Level) bLOS = false; else if (IsPointInCylinder(hitActor, destLoc, 16, 16)) break; else if (hitActor.bBlockSight && !hitActor.bHidden) bLOS = false; } if (!bLOS) break; } } if (!bLOS) { if (PointReachable(destLoc)) { rotation = Rotator(destLoc - Location); if (seekDistance == 0) nextLoc = destLoc; else if (!AIDirectionReachable(destLoc, rotation.Yaw, rotation.Pitch, 0, seekDistance, nextLoc)) bDone = true; if (!bDone && bDefendHome && !IsNearHome(nextLoc)) bDone = true; if (!bDone) // hack, because Unreal's movement code SUCKS { diffVect = nextLoc - Location; if (Physics == PHYS_Walking) diffVect *= vect(1,1,0); if (VSize(diffVect) < 20) bDone = true; else if (IsPointInCylinder(self, nextLoc, 10, 10)) bDone = true; } } else { MoveTarget = FindPathTo(destLoc); if (MoveTarget == None) bDone = true; else if (bDefendHome && !IsNearHome(MoveTarget.Location)) bDone = true; else nextLoc = MoveTarget.Location; } } else bDone = true; return (!bDone); } function bool PickDestination() { local bool bValid; bValid = false; if (/*(EnemyLastSeen <= 25.0) &&*/ (SeekLevel > 0)) { if (bSeekLocation) { bValid = true; destLoc = LastSeenPos; } else { bValid = AIPickRandomDestination(130, 250, 0, 0, 0, 0, 2, 1.0, destLoc); if (!bValid) { bValid = true; destLoc = Location + VRand()*50; } else destLoc += vect(0,0,1)*BaseEyeHeight; } } return (bValid); } function NavigationPoint GetOvershootDestination(float randomness, optional float focus) { local NavigationPoint navPoint, bestPoint; local float distance; local float score, bestScore; local int yaw; local rotator rot; local float yawCutoff; if (focus <= 0) focus = 0.6; yawCutoff = int(32768*focus); bestPoint = None; bestScore = 0; foreach ReachablePathnodes(Class'NavigationPoint', navPoint, None, distance) { if (distance < 1) distance = 1; rot = Rotator(navPoint.Location-Location); yaw = rot.Yaw + (16384*randomness); yaw = (yaw-Rotation.Yaw) & 0xFFFF; if (yaw > 32767) yaw -= 65536; yaw = abs(yaw); if (yaw <= yawCutoff) { score = yaw/distance; if ((bestPoint == None) || (score < bestScore)) { bestPoint = navPoint; bestScore = score; } } } return bestPoint; } function Tick(float deltaSeconds) { animTimer[1] += deltaSeconds; Global.Tick(deltaSeconds); UpdateActorVisibility(Enemy, deltaSeconds, 1.0, true); } function HandleLoudNoise(Name event, EAIEventState state, XAIParams params) { local Actor bestActor; local Pawn instigator; if (state == EAISTATE_Begin || state == EAISTATE_Pulse) { bestActor = params.bestActor; if ((bestActor != None) && (EnemyLastSeen > 2.0)) { instigator = Pawn(bestActor); if (instigator == None) instigator = bestActor.Instigator; if (instigator != None) { if (IsValidEnemy(instigator)) { SetSeekLocation(instigator, bestActor.Location, SEEKTYPE_Sound); destLoc = LastSeenPos; if (bInterruptSeek) GotoState('Seeking', 'GoToLocation'); } } } } } function HandleSighting(Pawn pawnSighted) { if ((EnemyLastSeen > 2.0) && IsValidEnemy(pawnSighted)) { SetSeekLocation(pawnSighted, pawnSighted.Location, SEEKTYPE_Sight); destLoc = LastSeenPos; if (bInterruptSeek) GotoState('Seeking', 'GoToLocation'); } } function BeginState() { StandUp(); Disable('AnimEnd'); destLoc = LastSeenPos; SetReactions(true, true, false, true, true, true, true, true, true, false, true, true); bCanConverse = False; bStasis = False; SetupWeapon(true); SetDistress(false); bInterruptSeek = false; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); Enable('AnimEnd'); ResetReactions(); bCanConverse = True; bStasis = True; StopBlendAnims(); SeekLevel = 0; } Begin: WaitForLanding(); PlayWaiting(); if ((Weapon != None) && bKeepWeaponDrawn && (Weapon.CockingSound != None) && !bSeekPostCombat) PlaySound(Weapon.CockingSound, SLOT_None,,, 1024); Acceleration = vect(0,0,0); if (!PickDestination()) Goto('DoneSeek'); GoToLocation: bInterruptSeek = true; Acceleration = vect(0,0,0); if ((DeusExWeapon(Weapon) != None) && DeusExWeapon(Weapon).CanReload() && !Weapon.IsInState('Reload')) DeusExWeapon(Weapon).ReloadAmmo(); if (bSeekPostCombat) PlayPostAttackSearchingSound(); else if (SeekType == SEEKTYPE_Sound) PlayPreAttackSearchingSound(); else if (SeekType == SEEKTYPE_Sight) { if (ReactionLevel > 0.5) PlayPreAttackSightingSound(); } else if ((SeekType == SEEKTYPE_Carcass) && bSeekLocation) PlayCarcassSound(); StopBlendAnims(); if ((SeekType == SEEKTYPE_Sight) && bSeekLocation) Goto('TurnToLocation'); EnableCheckDestLoc(true); while (GetNextLocation(useLoc)) { if (ShouldPlayWalk(useLoc)) PlayRunning(); MoveTo(useLoc, MaxDesiredSpeed); CheckDestLoc(useLoc); } EnableCheckDestLoc(false); if ((SeekType == SEEKTYPE_Guess) && bSeekLocation) { MoveTarget = GetOvershootDestination(0.5); if (MoveTarget != None) { if (ShouldPlayWalk(MoveTarget.Location)) PlayRunning(); MoveToward(MoveTarget, MaxDesiredSpeed); } if (AIPickRandomDestination(CollisionRadius*2, 200+FRand()*200, Rotation.Yaw, 0.75, Rotation.Pitch, 0.75, 2, 0.4, useLoc)) { if (ShouldPlayWalk(useLoc)) PlayRunning(); MoveTo(useLoc, MaxDesiredSpeed); } } TurnToLocation: Acceleration = vect(0,0,0); PlayTurning(); if ((SeekType == SEEKTYPE_Guess) && bSeekLocation) destLoc = Location + Vector(Rotation+(rot(0,1,0)*(Rand(16384)-8192)))*1000; if (bCanTurnHead) { Sleep(0); // needed to turn head LookAtVector(destLoc, true, false, true); TurnTo(Vector(DesiredRotation)*1000+Location); } else TurnTo(destLoc); bSeekLocation = false; bInterruptSeek = false; PlayWaiting(); Sleep(FRand()*1.5+3.0); LookAround: if (bCanTurnHead) { if (FRand() < 0.5) { if (!bSeekLocation) { PlayTurnHead(LOOK_Left, 1.0, 1.0); Sleep(1.0); } if (!bSeekLocation) { PlayTurnHead(LOOK_Forward, 1.0, 1.0); Sleep(0.5); } if (!bSeekLocation) { PlayTurnHead(LOOK_Right, 1.0, 1.0); Sleep(1.0); } } else { if (!bSeekLocation) { PlayTurnHead(LOOK_Right, 1.0, 1.0); Sleep(1.0); } if (!bSeekLocation) { PlayTurnHead(LOOK_Forward, 1.0, 1.0); Sleep(0.5); } if (!bSeekLocation) { PlayTurnHead(LOOK_Left, 1.0, 1.0); Sleep(1.0); } } PlayTurnHead(LOOK_Forward, 1.0, 1.0); Sleep(0.5); StopBlendAnims(); } else { if (!bSeekLocation) Sleep(1.0); } FindAnotherPlace: SeekLevel--; if (PickDestination()) Goto('GoToLocation'); DoneSeek: if (bSeekPostCombat) PlayTargetLostSound(); else PlaySearchGiveUpSound(); bSeekPostCombat = false; SeekPawn = None; if (Orders != 'Seeking') FollowOrders(); else GotoState('Wandering'); ContinueSeek: ContinueFromDoor: FinishAnim(); Goto('FindAnotherPlace'); } // ---------------------------------------------------------------------- // state Fleeing // // Run like a bat outta hell away from an actor. // ---------------------------------------------------------------------- State Fleeing { function ReactToInjury(Pawn instigatedBy, Name damageType, EHitLocation hitPos) { local Name currentState; local Pawn oldEnemy; local name newLabel; local bool bHateThisInjury; local bool bFearThisInjury; local bool bAttack; if ((health > 0) && (bLookingForInjury || bLookingForIndirectInjury)) { currentState = GetStateName(); bHateThisInjury = ShouldReactToInjuryType(damageType, bHateInjury, bHateIndirectInjury); bFearThisInjury = ShouldReactToInjuryType(damageType, bFearInjury, bFearIndirectInjury); if (bHateThisInjury) IncreaseAgitation(instigatedBy); if (bFearThisInjury) IncreaseFear(instigatedBy, 2.0); oldEnemy = Enemy; bAttack = false; if (SetEnemy(instigatedBy)) { if (!ShouldFlee()) { SwitchToBestWeapon(); if (Weapon != None) bAttack = true; } } else SetEnemy(instigatedBy, , true); if (bAttack) { SetDistressTimer(); SetNextState('HandlingEnemy'); } else { SetDistressTimer(); if (oldEnemy != Enemy) newLabel = 'Begin'; else newLabel = 'ContinueFlee'; SetNextState('Fleeing', newLabel); } GotoDisabledState(damageType, hitPos); } } function SetFall() { StartFalling('Fleeing', 'ContinueFlee'); } function FinishFleeing() { if (bLeaveAfterFleeing) GotoState('Wandering'); else FollowOrders(); } function bool InSeat(out vector newLoc) // hack { local Seat curSeat; local bool bSeat; bSeat = false; foreach RadiusActors(Class'Seat', curSeat, 200) { if (IsOverlapping(curSeat)) { bSeat = true; newLoc = curSeat.Location + vector(curSeat.Rotation+Rot(0, -16384, 0))*(CollisionRadius+curSeat.CollisionRadius+20); break; } } return (bSeat); } function Tick(float deltaSeconds) { UpdateActorVisibility(Enemy, deltaSeconds, 1.0, false); if (IsValidEnemy(Enemy)) { if (EnemyLastSeen > FearSustainTime) FinishFleeing(); } else if (!IsValidEnemy(Enemy, false)) FinishFleeing(); else if (!IsFearful()) FinishFleeing(); Global.Tick(deltaSeconds); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function AnimEnd() { PlayWaiting(); } function PickDestination() { local HidePoint hidePoint; local Actor waypoint; local float dist; local float score; local Vector vector1, vector2; local Rotator rotator1; local float tmpDist; local float bestDist; local float bestScore; local FleeCandidates candidates[5]; local int candidateCount; local int maxCandidates; local float maxDist; local int openSlot; local float maxScore; local int i; local bool bReplace; local float angle; local float magnitude; local int iterations; local NearbyProjectileList projList; local bool bSuccess; maxCandidates = 3; // must be <= size of candidates[] arrays maxDist = 10000; // Initialize the list of candidates for (i=0; i<maxCandidates; i++) { candidates[i].score = -1; candidates[i].dist = maxDist+1; } candidateCount = 0; MoveTarget = None; destPoint = None; if (bAvoidHarm) { GetProjectileList(projList, Location); if (IsLocationDangerous(projList, Location)) { vector1 = ComputeAwayVector(projList); rotator1 = Rotator(vector1); if (AIDirectionReachable(Location, rotator1.Yaw, rotator1.Pitch, CollisionRadius+24, VSize(vector1), destLoc)) return; // eck -- hack!!! } } if (Enemy != None) { foreach RadiusActors(Class'HidePoint', hidePoint, maxDist) { // Can the boogeyman see our hiding spot? if (!enemy.LineOfSightTo(hidePoint)) { // More importantly, can we REACH our hiding spot? waypoint = GetNextWaypoint(hidePoint); if (waypoint != None) { // How far is it to the hiding place? dist = VSize(hidePoint.Location - Location); // Determine vectors to the waypoint and our enemy vector1 = enemy.Location - Location; vector2 = waypoint.Location - Location; // Strip out magnitudes from the vectors tmpDist = VSize(vector1); if (tmpDist > 0) vector1 /= tmpDist; tmpDist = VSize(vector2); if (tmpDist > 0) vector2 /= tmpDist; // Add them vector1 += vector2; // Compute a score (a function of angle) score = VSize(vector1); score = 4-(score*score); // Find an empty slot for this candidate openSlot = -1; bestScore = score; bestDist = dist; for (i=0; i<maxCandidates; i++) { // Can we replace the candidate in this slot? if (bestScore > candidates[i].score) bReplace = TRUE; else if ((bestScore == candidates[i].score) && (bestDist < candidates[i].dist)) bReplace = TRUE; else bReplace = FALSE; if (bReplace) { bestScore = candidates[i].score; bestDist = candidates[i].dist; openSlot = i; } } // We found an open slot -- put our candidate here if (openSlot >= 0) { candidates[openSlot].point = hidePoint; candidates[openSlot].waypoint = waypoint; candidates[openSlot].location = waypoint.Location; candidates[openSlot].score = score; candidates[openSlot].dist = dist; if (candidateCount < maxCandidates) candidateCount++; } } } } // Any candidates? if (candidateCount > 0) { // Find a random candidate // (candidates moving AWAY from the enemy have a higher // probability of being chosen than candidates moving // TOWARDS the enemy) maxScore = 0; for (i=0; i<candidateCount; i++) maxScore += candidates[i].score; score = FRand() * maxScore; for (i=0; i<candidateCount; i++) { score -= candidates[i].score; if (score <= 0) break; } destPoint = candidates[i].point; MoveTarget = candidates[i].waypoint; destLoc = candidates[i].location; } else { iterations = 4; magnitude = 400*(FRand()*0.4+0.8); // 400, +/-20% rotator1 = Rotator(Location-Enemy.Location); if (!AIPickRandomDestination(100, magnitude, rotator1.Yaw, 0.6, rotator1.Pitch, 0.6, iterations, FRand()*0.4+0.35, destLoc)) destLoc = Location+(VRand()*1200); // we give up } } else destLoc = Location+(VRand()*1200); // we give up } function BeginState() { StandUp(); Disable('AnimEnd'); //Disable('Bump'); BlockReactions(); if (!bCower) bCanConverse = False; bStasis = False; SetupWeapon(false, true); SetDistress(true); EnemyReadiness = 1.0; //ReactionLevel = 1.0; SeekPawn = None; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); Enable('AnimEnd'); //Enable('Bump'); ResetReactions(); if (!bCower) bCanConverse = True; bStasis = True; } Begin: //EnemyLastSeen = 0; destPoint = None; Surprise: if ((1.0-ReactionLevel)*SurprisePeriod < 0.25) Goto('Flee'); Acceleration=vect(0,0,0); PlaySurpriseSound(); PlayWaiting(); Sleep(FRand()*0.5); if (Enemy != None) TurnToward(Enemy); if (bCower) Goto('Flee'); Sleep(FRand()*0.5+0.5); Flee: if (bLeaveAfterFleeing) { bTransient = true; bDisappear = true; } if (bCower) Goto('Cower'); WaitForLanding(); PickDestination(); Moving: Sleep(0.0); if (enemy == None) { Acceleration = vect(0,0,0); PlayWaiting(); Sleep(2.0); FinishFleeing(); } // Move from pathnode to pathnode until we get where we're going if (destPoint != None) { EnableCheckDestLoc(true); while (MoveTarget != None) { if (ShouldPlayWalk(MoveTarget.Location)) PlayRunning(); MoveToward(MoveTarget, MaxDesiredSpeed); CheckDestLoc(MoveTarget.Location, true); if (enemy.bDetectable && enemy.AICanSee(destPoint, 1.0, false, false, false, true) > 0) { PickDestination(); EnableCheckDestLoc(false); Goto('Moving'); } if (MoveTarget == destPoint) break; MoveTarget = FindPathToward(destPoint); } EnableCheckDestLoc(false); } else if (PointReachable(destLoc)) { if (ShouldPlayWalk(destLoc)) PlayRunning(); MoveTo(destLoc, MaxDesiredSpeed); if (enemy.bDetectable && enemy.AICanSee(Self, 1.0, false, false, true, true) > 0) { PickDestination(); Goto('Moving'); } } else { PickDestination(); Goto('Moving'); } Pausing: Acceleration = vect(0,0,0); if (enemy != None) { if (HidePoint(destPoint) != None) { if (ShouldPlayTurn(Location + HidePoint(destPoint).faceDirection)) PlayTurning(); TurnTo(Location + HidePoint(destPoint).faceDirection); } Enable('AnimEnd'); TweenToWaiting(0.2); while (AICanSee(enemy, 1.0, false, false, true, true) <= 0) Sleep(0.25); Disable('AnimEnd'); FinishAnim(); } Goto('Flee'); Cower: if (!InSeat(useLoc)) Goto('CowerContinue'); PlayRunning(); MoveTo(useLoc, MaxDesiredSpeed); CowerContinue: Acceleration = vect(0,0,0); PlayCowerBegin(); FinishAnim(); PlayCowering(); // behavior 3 - cower and occasionally make short runs while (true) { Sleep(FRand()*3+6); PlayCowerEnd(); FinishAnim(); if (AIPickRandomDestination(60, 150, 0, 0, 0, 0, 2, FRand()*0.3+0.6, useLoc)) { if (ShouldPlayWalk(useLoc)) PlayRunning(); MoveTo(useLoc, MaxDesiredSpeed); } PlayCowerBegin(); FinishAnim(); PlayCowering(); } /* behavior 2 - cower forever // don't stop cowering while (true) Sleep(1.0); */ /* behavior 1 - cower only when enemy watching if (enemy != None) { while (AICanSee(enemy, 1.0, false, false, true, true) > 0) Sleep(0.25); } PlayCowerEnd(); FinishAnim(); Goto('Pausing'); */ ContinueFlee: ContinueFromDoor: FinishAnim(); PlayRunning(); if (bCower) Goto('Cower'); else Goto('Moving'); } // ---------------------------------------------------------------------- // state Attacking // // Kill! Kill! Kill! Kill! // ---------------------------------------------------------------------- State Attacking { function ReactToInjury(Pawn instigatedBy, Name damageType, EHitLocation hitPos) { local Pawn oldEnemy; local bool bHateThisInjury; local bool bFearThisInjury; if ((health > 0) && (bLookingForInjury || bLookingForIndirectInjury)) { oldEnemy = Enemy; bHateThisInjury = ShouldReactToInjuryType(damageType, bHateInjury, bHateIndirectInjury); bFearThisInjury = ShouldReactToInjuryType(damageType, bFearInjury, bFearIndirectInjury); if (bHateThisInjury) IncreaseAgitation(instigatedBy, 1.0); if (bFearThisInjury) IncreaseFear(instigatedBy, 2.0); if (ReadyForNewEnemy()) SetEnemy(instigatedBy); if (ShouldFlee()) { SetDistressTimer(); PlayCriticalDamageSound(); if (RaiseAlarm == RAISEALARM_BeforeFleeing) SetNextState('Alerting'); else SetNextState('Fleeing'); } else { SetDistressTimer(); if (oldEnemy != Enemy) PlayNewTargetSound(); SetNextState('Attacking', 'ContinueAttack'); } GotoDisabledState(damageType, hitPos); } } function SetFall() { StartFalling('Attacking', 'ContinueAttack'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function Reloading(DeusExWeapon reloadWeapon, float reloadTime) { Global.Reloading(reloadWeapon, reloadTime); if (bReadyToReload) if (IsWeaponReloading()) if (!IsHandToHand()) TweenToShoot(0); } function EDestinationType PickDestination() { local vector distVect; local vector tempVect; local rotator enemyDir; local float magnitude; local float calcMagnitude; local int iterations; local EDestinationType destType; local NearbyProjectileList projList; destPoint = None; destLoc = vect(0, 0, 0); destType = DEST_Failure; if (enemy == None) return (destType); if (bCrouching && (CrouchTimer > 0)) destType = DEST_SameLocation; if (destType == DEST_Failure) { if (AICanShoot(enemy, true, false, 0.025) || ActorReachable(enemy)) { destType = ComputeBestFiringPosition(tempVect); if (destType == DEST_NewLocation) destLoc = tempVect; } } if (destType == DEST_Failure) { MoveTarget = FindPathToward(enemy); if (MoveTarget != None) { if (!bDefendHome || IsNearHome(MoveTarget.Location)) { if (bAvoidHarm) GetProjectileList(projList, MoveTarget.Location); if (!bAvoidHarm || !IsLocationDangerous(projList, MoveTarget.Location)) { destPoint = MoveTarget; destType = DEST_NewLocation; } } } } // Default behavior, so they don't just stand there... if (destType == DEST_Failure) { enemyDir = Rotator(Enemy.Location - Location); if (AIPickRandomDestination(60, 150, enemyDir.Yaw, 0.5, enemyDir.Pitch, 0.5, 2, FRand()*0.4+0.35, tempVect)) { if (!bDefendHome || IsNearHome(tempVect)) { destType = DEST_NewLocation; destLoc = tempVect; } } } return (destType); } function bool FireIfClearShot() { local DeusExWeapon dxWeapon; dxWeapon = DeusExWeapon(Weapon); if (dxWeapon != None) { if ((dxWeapon.AIFireDelay > 0) && (FireTimer > 0)) return false; else if (AICanShoot(enemy, true, true, 0.025)) { Weapon.Fire(0); FireTimer = dxWeapon.AIFireDelay; return true; } else return false; } else return false; } function CheckAttack(bool bPlaySound) { local bool bCriticalDamage; local bool bOutOfAmmo; local Pawn oldEnemy; local bool bAllianceSwitch; oldEnemy = enemy; bAllianceSwitch = false; if (!IsValidEnemy(enemy)) { if (IsValidEnemy(enemy, false)) bAllianceSwitch = true; SetEnemy(None, 0, true); } if (enemy == None) { if (Orders == 'Attacking') { FindOrderActor(); SetEnemy(Pawn(OrderActor), 0, true); } } if (ReadyForNewEnemy()) FindBestEnemy(false); if (enemy == None) { Enemy = oldEnemy; // hack if (bPlaySound) { if (bAllianceSwitch) PlayAllianceFriendlySound(); else PlayAreaSecureSound(); } Enemy = None; if (Orders != 'Attacking') FollowOrders(); else GotoState('Wandering'); return; } SwitchToBestWeapon(); if (bCrouching && (CrouchTimer <= 0) && !ShouldCrouch()) { EndCrouch(); TweenToShoot(0.15); } bCriticalDamage = False; bOutOfAmmo = False; if (ShouldFlee()) bCriticalDamage = True; else if (Weapon == None) bOutOfAmmo = True; else if (Weapon.ReloadCount > 0) { if (Weapon.AmmoType == None) bOutOfAmmo = True; else if (Weapon.AmmoType.AmmoAmount < 1) bOutOfAmmo = True; } if (bCriticalDamage || bOutOfAmmo) { if (bPlaySound) { if (bCriticalDamage) PlayCriticalDamageSound(); else if (bOutOfAmmo) PlayOutOfAmmoSound(); } if (RaiseAlarm == RAISEALARM_BeforeFleeing) GotoState('Alerting'); else GotoState('Fleeing'); } else if (bPlaySound && (oldEnemy != Enemy)) PlayNewTargetSound(); } function Tick(float deltaSeconds) { local bool bCanSee; local float yaw; local vector lastLocation; local Pawn lastEnemy; local float surpriseTime; Global.Tick(deltaSeconds); if (CrouchTimer > 0) { CrouchTimer -= deltaSeconds; if (CrouchTimer < 0) CrouchTimer = 0; } EnemyTimer += deltaSeconds; UpdateActorVisibility(Enemy, deltaSeconds, 1.0, false); if ((Enemy != None) && HasEnemyTimedOut()) { lastLocation = Enemy.Location; lastEnemy = Enemy; FindBestEnemy(true); if (Enemy == None) { SetSeekLocation(lastEnemy, lastLocation, SEEKTYPE_Guess, true); GotoState('Seeking'); } } else if (bCanFire && (Enemy != None)) { ViewRotation = Rotator(Enemy.Location-Location); if (bFacingTarget) FireIfClearShot(); else if (!bMustFaceTarget) { yaw = (ViewRotation.Yaw-Rotation.Yaw) & 0xFFFF; if (yaw >= 32768) yaw -= 65536; yaw = Abs(yaw)*360/32768; // 0-180 x 2 if (yaw <= FireAngle) FireIfClearShot(); } } //UpdateReactionLevel(true, deltaSeconds); } function bool IsHandToHand() { if (Weapon != None) { if (DeusExWeapon(Weapon) != None) { if (DeusExWeapon(Weapon).bHandToHand) return true; else return false; } else return false; } else return false; } function bool ReadyForWeapon() { local bool bReady; bReady = false; if (DeusExWeapon(weapon) != None) { if (DeusExWeapon(weapon).bReadyToFire) if (!IsWeaponReloading()) bReady = true; } if (!bReady) if (enemy == None) bReady = true; if (!bReady) if (!AICanShoot(enemy, true, false, 0.025)) bReady = true; return (bReady); } function bool ShouldCrouch() { if (bCanCrouch && !Region.Zone.bWaterZone && !IsHandToHand() && ((enemy != None) && (VSize(enemy.Location-Location) > 300)) && ((DeusExWeapon(Weapon) == None) || DeusExWeapon(Weapon).bUseWhileCrouched)) return true; else return false; } function StartCrouch() { if (!bCrouching) { bCrouching = true; SetBasedPawnSize(CollisionRadius, GetCrouchHeight()); CrouchTimer = 1.0+FRand()*0.5; } } function EndCrouch() { if (bCrouching) { bCrouching = false; ResetBasedPawnSize(); } } function BeginState() { StandUp(); // hack if (MaxRange < MinRange+10) MaxRange = MinRange+10; bCanFire = false; bFacingTarget = false; SwitchToBestWeapon(); //EnemyLastSeen = 0; BlockReactions(); bCanConverse = False; bAttacking = True; bStasis = False; SetDistress(true); CrouchTimer = 0; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); bCanFire = false; bFacingTarget = false; ResetReactions(); bCanConverse = True; bAttacking = False; bStasis = True; bReadyToReload = false; EndCrouch(); } Begin: if (Enemy == None) GotoState('Seeking'); //EnemyLastSeen = 0; CheckAttack(false); Surprise: if ((1.0-ReactionLevel)*SurprisePeriod < 0.25) Goto('BeginAttack'); Acceleration=vect(0,0,0); PlaySurpriseSound(); PlayWaiting(); while (ReactionLevel < 1.0) { TurnToward(Enemy); Sleep(0); } BeginAttack: EnemyReadiness = 1.0; ReactionLevel = 1.0; if (PlayerAgitationTimer > 0) PlayAllianceHostileSound(); else PlayTargetAcquiredSound(); if (PlayBeginAttack()) { Acceleration = vect(0,0,0); TurnToward(enemy); FinishAnim(); } RunToRange: bCanFire = false; bFacingTarget = false; bReadyToReload = false; EndCrouch(); if (Physics == PHYS_Falling) TweenToRunning(0.05); WaitForLanding(); if (!IsWeaponReloading() || bCrouching) { if (ShouldPlayTurn(Enemy.Location)) PlayTurning(); TurnToward(enemy); } else Sleep(0); bCanFire = true; while (PickDestination() == DEST_NewLocation) { if (bCanStrafe && ShouldStrafe()) { PlayRunningAndFiring(); if (destPoint != None) StrafeFacing(destPoint.Location, enemy); else StrafeFacing(destLoc, enemy); bFacingTarget = true; } else { bFacingTarget = false; PlayRunning(); if (destPoint != None) MoveToward(destPoint, MaxDesiredSpeed); else MoveTo(destLoc, MaxDesiredSpeed); } CheckAttack(true); } Fire: bCanFire = false; bFacingTarget = false; Acceleration = vect(0, 0, 0); SwitchToBestWeapon(); if (FRand() > 0.5) bUseSecondaryAttack = true; else bUseSecondaryAttack = false; if (IsHandToHand()) TweenToAttack(0.15); else if (ShouldCrouch() && (FRand() < CrouchRate)) { TweenToCrouchShoot(0.15); FinishAnim(); StartCrouch(); } else TweenToShoot(0.15); if (!IsWeaponReloading() || bCrouching) TurnToward(enemy); FinishAnim(); bReadyToReload = true; ContinueFire: while (!ReadyForWeapon()) { if (PickDestination() != DEST_SameLocation) Goto('RunToRange'); CheckAttack(true); if (!IsWeaponReloading() || bCrouching) TurnToward(enemy); else Sleep(0); } CheckAttack(true); if (!FireIfClearShot()) Goto('ContinueAttack'); bReadyToReload = false; if (bCrouching) PlayCrouchShoot(); else if (IsHandToHand()) PlayAttack(); else PlayShoot(); FinishAnim(); if (FRand() > 0.5) bUseSecondaryAttack = true; else bUseSecondaryAttack = false; bReadyToReload = true; if (!IsHandToHand()) { if (bCrouching) TweenToCrouchShoot(0); else TweenToShoot(0); } CheckAttack(true); if (PickDestination() != DEST_NewLocation) { if (!IsWeaponReloading() || bCrouching) TurnToward(enemy); else Sleep(0); Goto('ContinueFire'); } Goto('RunToRange'); ContinueAttack: ContinueFromDoor: CheckAttack(true); if (PickDestination() != DEST_NewLocation) Goto('Fire'); else Goto('RunToRange'); } // ---------------------------------------------------------------------- // state Alerting // // Warn other NPCs that an enemy is about // ---------------------------------------------------------------------- State Alerting { function SetFall() { StartFalling('Alerting', 'ContinueAlert'); } function Tick(float deltaSeconds) { Global.Tick(deltaSeconds); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function Bump(actor bumper) { if (bAcceptBump) { if (bumper == AlarmActor) { bAcceptBump = False; GotoState('Alerting', 'SoundAlarm'); } } // Handle conversations, if need be Global.Bump(bumper); } function bool IsAlarmReady(Actor actorAlarm) { local bool bReady; local AlarmUnit alarm; bReady = false; alarm = AlarmUnit(actorAlarm); if ((alarm != None) && !alarm.bDeleteMe) if (!alarm.bActive) if ((alarm.associatedPawn == None) || (alarm.associatedPawn == self)) bReady = true; return bReady; } function TriggerAlarm() { if ((AlarmActor != None) && !AlarmActor.bDeleteMe) { if (AlarmActor.hackStrength > 0) // make sure the alarm hasn't been hacked AlarmActor.Trigger(self, Enemy); } } function bool IsAlarmInRange(AlarmUnit alarm) { local bool bInRange; bInRange = false; if ((alarm != None) && !alarm.bDeleteMe) if ((VSize((alarm.Location-Location)*vect(1,1,0)) < (CollisionRadius+alarm.CollisionRadius+24)) && (Abs(alarm.Location.Z-Location.Z) < (CollisionHeight+alarm.CollisionHeight))) bInRange = true; return (bInRange); } function vector FindAlarmPosition(Actor alarm) { local vector alarmPos; alarmPos = alarm.Location; alarmPos += vector(alarm.Rotation.Yaw*rot(0,1,0))*(CollisionRadius+alarm.CollisionRadius); return (alarmPos); } function bool GetNextAlarmPoint(AlarmUnit alarm) { local vector alarmPoint; local bool bValid; destPoint = None; destLoc = vect(0,0,0); bValid = false; if ((alarm != None) && !alarm.bDeleteMe) { alarmPoint = FindAlarmPosition(alarm); if (PointReachable(alarmPoint)) { destLoc = alarmPoint; bValid = true; } else { MoveTarget = FindPathTo(alarmPoint); if (MoveTarget != None) { destPoint = MoveTarget; bValid = true; } } } return (bValid); } function AlarmUnit FindTarget() { local ScriptedPawn pawnAlly; local AlarmUnit alarm; local float dist; local AlarmUnit bestAlarm; local float bestDist; bestAlarm = None; // Do we have any allies on this level? foreach AllActors(Class'ScriptedPawn', pawnAlly) if (GetPawnAllianceType(pawnAlly) == ALLIANCE_Friendly) break; // Yes, so look for an alarm box that isn't active... if (pawnAlly != None) { foreach RadiusActors(Class'AlarmUnit', alarm, 2400) { if (GetAllianceType(alarm.Alliance) != ALLIANCE_Hostile) { dist = VSize((Location-alarm.Location)*vect(1,1,2)); // use squished sphere if ((bestAlarm == None) || (dist < bestDist)) { bestAlarm = alarm; bestDist = dist; } } } // Is the nearest alarm already going off? And can we reach it? if (!IsAlarmReady(bestAlarm) || !GetNextAlarmPoint(bestAlarm)) bestAlarm = None; } // Return our target alarm box return (bestAlarm); } function bool PickDestination() { local bool bDest; local AlarmUnit alarm; // Init destPoint = None; destLoc = vect(0, 0, 0); bDest = false; // Find an alarm we can trigger alarm = FindTarget(); if (alarm != None) { // Find a way to get there AlarmActor = alarm; alarm.associatedPawn = self; bDest = true; // if alarm != none, we've already computed the route to the alarm } // Return TRUE if we were successful return (bDest); } function BeginState() { StandUp(); //Disable('AnimEnd'); bAcceptBump = False; bCanConverse = False; AlarmActor = None; bStasis = False; BlockReactions(); SetupWeapon(false); SetDistress(false); EnemyReadiness = 1.0; ReactionLevel = 1.0; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); ResetReactions(); bAcceptBump = False; //Enable('AnimEnd'); bCanConverse = True; if (AlarmActor != None) if (AlarmActor.associatedPawn == self) AlarmActor.associatedPawn = None; AlarmActor = None; bStasis = True; } Begin: if (Enemy == None) GotoState('Seeking'); //EnemyLastSeen = 0; destPoint = None; if (RaiseAlarm == RAISEALARM_Never) GotoState('Fleeing'); if (AlarmTimer > 0) PlayGoingForAlarmSound(); Alert: if (AlarmTimer > 0) Goto('Done'); WaitForLanding(); if (!PickDestination()) Goto('Done'); Moving: // Can we go somewhere? bAcceptBump = True; EnableCheckDestLoc(true); while (true) { if (destPoint != None) { if (ShouldPlayWalk(MoveTarget.Location)) PlayRunning(); MoveToward(MoveTarget, MaxDesiredSpeed); CheckDestLoc(MoveTarget.Location, true); } else { if (ShouldPlayWalk(destLoc)) PlayRunning(); MoveTo(destLoc, MaxDesiredSpeed); CheckDestLoc(destLoc); } if (IsAlarmInRange(AlarmActor)) break; else if (!GetNextAlarmPoint(AlarmActor)) break; } EnableCheckDestLoc(false); SoundAlarm: Acceleration=vect(0,0,0); bAcceptBump = False; if (IsAlarmInRange(AlarmActor)) { TurnToward(AlarmActor); PlayPushing(); FinishAnim(); TriggerAlarm(); } Done: bAcceptBump = False; if (RaiseAlarm == RAISEALARM_BeforeAttacking) GotoState('Attacking'); else GotoState('Fleeing'); ContinueAlert: ContinueFromDoor: Goto('Alert'); } // ---------------------------------------------------------------------- // state Shadowing // // Quietly tail another character // ---------------------------------------------------------------------- State Shadowing { function SetFall() { StartFalling('Shadowing', 'ContinueShadow'); } function Tick(float deltaSeconds) { local bool bMove; local float deltaValue; Global.Tick(deltaSeconds); deltaValue = deltaSeconds; // If we're running, and we can see our target, STOP RUNNING! if (bRunningStealthy) { UpdateActorVisibility(orderActor, deltaValue, 0.0, false); deltaValue = 0; if (EnemyLastSeen <= 0) { bRunningStealthy = False; PlayWalking(); DesiredSpeed = GetWalkingSpeed(); } } // Are we stopped? if (bPausing) { // Can we see our target? bMove = False; UpdateActorVisibility(orderActor, deltaValue, 0.5, false); deltaValue = 0; // No -- move toward him! if (EnemyLastSeen > 0.5) bMove = True; // We can see him, and we're staring... else if (bStaring) { // ...can he see us staring at him? if ((Pawn(orderActor) != None) && (Pawn(orderActor).AICanSee(self, , false, true, false, false) > 0)) bMove = True; // Time to look inconspicuous } // Move if we need to if (bMove) { if (bStaring) GotoState('Shadowing', 'StopStaring'); else GotoState('Shadowing', 'StopPausing'); bPausing = False; bStaring = False; } } } function Bump(actor bumper) { if (bAcceptBump) { // If we get bumped by another actor while we wait, start wandering again bAcceptBump = False; bPausing = False; bStaring = False; Disable('AnimEnd'); GotoState('Shadowing', 'Shadow'); } // Handle conversations, if need be Global.Bump(bumper); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function AnimEnd() { PlayWaiting(); } function float DistanceToTarget() { return (VSize(Location-orderActor.Location)); } function bool PickDestination() { local Actor destActor; local Vector distVect; local Rotator relativeRotation; local float magnitude; local float minDist; local float maxDist; local float bestDist; local bool bDest; local float dist; // Init destPoint = None; destLoc = vect(0, 0, 0); // Conveniences destActor = orderActor; minDist = 400; maxDist = 700; bestDist = (maxDist+minDist)*0.5; distVect = Location - destActor.Location; magnitude = VSize(distVect); bDest = False; // Can we see the target? if (AICanSee(destActor, , false, false, false, true) > 0) { relativeRotation = Rotator(distVect); // How far will we go? dist = (wanderlust*300+150) * (FRand()*0.2+0.9); // 150-450, +/-10% // Move around inconspicuously, like we're just wandering if (magnitude < minDist) // too close -- move away bDest = AIPickRandomDestination(100, dist, relativeRotation.Yaw, 0.8, relativeRotation.Pitch, 0.8, 3, FRand()*0.4+0.35, destLoc); else if (magnitude < maxDist) // just right -- move normally bDest = AIPickRandomDestination(100, dist, relativeRotation.Yaw+32768, 0, -relativeRotation.Pitch, 0, 2, FRand()*0.4+0.35, destLoc); else // too far -- move closer bDest = AIPickRandomDestination(100, dist, relativeRotation.Yaw+32768, 0.8, -relativeRotation.Pitch, 0.8, 3, FRand()*0.4+0.35, destLoc); } // Nope -- find a path towards him else { MoveTarget = FindPathToward(destActor); if (MoveTarget != None) { if (!MoveTarget.Region.Zone.bWaterZone && (MoveTarget.Physics != PHYS_Falling)) { destPoint = MoveTarget; bDest = True; } } } // Return TRUE if we found a place to go return (bDest); } function BeginState() { StandUp(); Disable('AnimEnd'); bRunningStealthy = False; bPausing = False; bStaring = False; bStasis = False; SetupWeapon(false); SetDistress(false); SeekPawn = None; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); bAcceptBump = False; Enable('AnimEnd'); bRunningStealthy = False; bPausing = False; bStaring = False; bStasis = True; } Begin: EnemyLastSeen = 0; destPoint = None; Shadow: WaitForLanding(); Moving: Sleep(0.0); // Can we go somewhere? if (PickDestination()) { // Are we going to a navigation point? if (destPoint != None) { if (MoveTarget != None) { // Run if we're too far away, and we can't see our target if ((DistanceToTarget() > 900) && (AICanSee(orderActor, , false, true, true, true) <= 0)) { bRunningStealthy = True; if (ShouldPlayWalk(MoveTarget.Location)) PlayRunning(); MoveToward(MoveTarget, MaxDesiredSpeed); } // Otherwise, walk nonchalantly else { bRunningStealthy = False; if (ShouldPlayWalk(MoveTarget.Location)) PlayWalking(); MoveToward(MoveTarget, GetWalkingSpeed()); } } } // No pathnode, so walk to a point else { bRunningStealthy = False; if (ShouldPlayWalk(destLoc)) PlayWalking(); MoveTo(destLoc, GetWalkingSpeed()); } } // Can we see the target? If not, keep walking if (AICanSee(orderActor, , false, false, false, true) <= 0) Goto('Moving'); Pausing: // Stop bRunningStealthy = False; Acceleration = vect(0, 0, 0); // Can the target see us? If not, stare! if (orderActor.IsA('Pawn') && Pawn(orderActor).AICanSee(self, , false, true, false, false) <= 0) Goto('Staring'); // Stop normally sleepTime = 6.0; Enable('AnimEnd'); TweenToWaiting(0.2); bAcceptBump = True; sleepTime *= (-0.9*restlessness) + 1; bStaring = False; bPausing = True; Sleep(sleepTime); StopPausing: // Time to move again bPausing = False; bStaring = False; Disable('AnimEnd'); bAcceptBump = False; FinishAnim(); Goto('Shadow'); Staring: // Stare at the target PlayTurning(); TurnToward(orderActor); Enable('AnimEnd'); TweenToWaiting(0.2); // Don't move 'til he looks at us bAcceptBump = True; bStaring = True; bPausing = True; while (true) { PlayTurning(); TurnToward(orderActor); TweenToWaiting(0.2); Sleep(0.25); } StopStaring: // He's looking, or we can't see him -- time to move bPausing = False; bStaring = False; Disable('AnimEnd'); bAcceptBump = False; FinishAnim(); Goto('Shadow'); ContinueShadow: ContinueFromDoor: FinishAnim(); PlayRunning(); Goto('Moving'); } // ---------------------------------------------------------------------- // state Following // // Follow an actor // ---------------------------------------------------------------------- state Following { function SetFall() { StartFalling('Following', 'ContinueFollow'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function Tick(float deltaSeconds) { Global.Tick(deltaSeconds); if (BackpedalTimer >= 0) BackpedalTimer += deltaSeconds; animTimer[1] += deltaSeconds; if ((Physics == PHYS_Walking) && (orderActor != None)) { if (Acceleration == vect(0,0,0)) LookAtActor(orderActor, true, true, true, 0, 0.25); else PlayTurnHead(LOOK_Forward, 1.0, 0.25); } } function bool PickDestination() { local float dist; local float extra; local float distMax; local int dir; local rotator rot; local bool bSuccess; bSuccess = false; destPoint = None; destLoc = vect(0, 0, 0); extra = orderActor.CollisionRadius + CollisionRadius; dist = VSize(orderActor.Location - Location); dist -= extra; if (dist < 0) dist = 0; if ((dist > 180) || (AICanSee(orderActor, , false, false, false, true) <= 0)) { if (ActorReachable(orderActor)) { rot = Rotator(orderActor.Location - Location); distMax = (dist-180)+45; if (distMax > 80) distMax = 80; bSuccess = AIDirectionReachable(Location, rot.Yaw, rot.Pitch, 0, distMax, destLoc); } else { MoveTarget = FindPathToward(orderActor); if (MoveTarget != None) { destPoint = MoveTarget; bSuccess = true; } } BackpedalTimer = -1; } else if (dist < 60) { if (BackpedalTimer < 0) BackpedalTimer = 0; if (BackpedalTimer > 1.0) // give the player enough time to converse, if he wants to { rot = Rotator(Location - orderActor.Location); bSuccess = AIDirectionReachable(orderActor.Location, rot.Yaw, rot.Pitch, 60+extra, 120+extra, destLoc); } } else BackpedalTimer = -1; return (bSuccess); } function BeginState() { StandUp(); //Disable('AnimEnd'); bStasis = False; SetupWeapon(false); SetDistress(false); BackpedalTimer = -1; SeekPawn = None; EnableCheckDestLoc(true); } function EndState() { EnableCheckDestLoc(false); bAcceptBump = False; //Enable('AnimEnd'); bStasis = True; StopBlendAnims(); } Begin: Acceleration = vect(0, 0, 0); destPoint = None; if (orderActor == None) GotoState('Standing'); if (!PickDestination()) Goto('Wait'); Follow: if (destPoint != None) { if (MoveTarget != None) { if (ShouldPlayWalk(MoveTarget.Location)) PlayRunning(); MoveToward(MoveTarget, MaxDesiredSpeed); CheckDestLoc(MoveTarget.Location, true); } else Sleep(0.0); // this shouldn't happen } else { if (ShouldPlayWalk(destLoc)) PlayRunning(); MoveTo(destLoc, MaxDesiredSpeed); CheckDestLoc(destLoc); } if (PickDestination()) Goto('Follow'); Wait: //PlayTurning(); //TurnToward(orderActor); PlayWaiting(); WaitLoop: Acceleration=vect(0,0,0); Sleep(0.0); if (!PickDestination()) Goto('WaitLoop'); else Goto('Follow'); ContinueFollow: ContinueFromDoor: Acceleration=vect(0,0,0); if (PickDestination()) Goto('Follow'); else Goto('Wait'); } // ---------------------------------------------------------------------- // state WaitingFor // // Wait for a pawn to become visible, then move to it // ---------------------------------------------------------------------- state WaitingFor { function SetFall() { StartFalling('WaitingFor', 'ContinueFollow'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function Bump(actor bumper) { // If we hit the guy we're going to, end the state if (bumper == OrderActor) GotoState('WaitingFor', 'Done'); // Handle conversations, if need be Global.Bump(bumper); } function Touch(actor toucher) { // If we hit the guy we're going to, end the state if (toucher == OrderActor) GotoState('WaitingFor', 'Done'); // Handle conversations, if need be Global.Touch(toucher); } function BeginState() { StandUp(); //BlockReactions(); SetupWeapon(false); SetDistress(false); bStasis = True; SeekPawn = None; EnableCheckDestLoc(true); } function EndState() { EnableCheckDestLoc(false); //ResetReactions(); bStasis = True; } Begin: Acceleration = vect(0, 0, 0); if (orderActor == None) GotoState('Idle'); PlayWaiting(); Wait: Sleep(1.0); if (AICanSee(orderActor, 1.0, false, true, false, true) <= 0) Goto('Wait'); bStasis = False; Follow: if (IsOverlapping(orderActor)) Goto('Done'); MoveTarget = GetNextWaypoint(orderActor); if ((MoveTarget != None) && (!MoveTarget.Region.Zone.bWaterZone) && (MoveTarget.Physics != PHYS_Falling)) { if ((MoveTarget == orderActor) && MoveTarget.IsA('Pawn')) { if (GetNextVector(orderActor, useLoc)) { if (ShouldPlayWalk(useLoc)) PlayRunning(); MoveTo(useLoc, MaxDesiredSpeed); CheckDestLoc(useLoc); } else Goto('Pause'); } else { if (ShouldPlayWalk(MoveTarget.Location)) PlayRunning(); MoveToward(MoveTarget, MaxDesiredSpeed); CheckDestLoc(MoveTarget.Location, true); } if (IsOverlapping(orderActor)) Goto('Done'); else Goto('Follow'); } Pause: Acceleration = vect(0, 0, 0); TurnToward(orderActor); PlayWaiting(); Sleep(1.0); Goto('Follow'); Done: GotoState('Standing'); ContinueFollow: ContinueFromDoor: PlayRunning(); Goto('Follow'); } // ---------------------------------------------------------------------- // state GoingTo // // Move to an actor. // ---------------------------------------------------------------------- state GoingTo { function SetFall() { StartFalling('GoingTo', 'ContinueGo'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function Bump(actor bumper) { // If we hit the guy we're going to, end the state if (bumper == OrderActor) GotoState('GoingTo', 'Done'); // Handle conversations, if need be Global.Bump(bumper); } function Touch(actor toucher) { // If we hit the guy we're going to, end the state if (toucher == OrderActor) GotoState('GoingTo', 'Done'); // Handle conversations, if need be Global.Touch(toucher); } function BeginState() { StandUp(); //BlockReactions(); SetupWeapon(false); SetDistress(false); bStasis = False; SeekPawn = None; EnableCheckDestLoc(true); } function EndState() { EnableCheckDestLoc(false); //ResetReactions(); bStasis = True; } Begin: Acceleration = vect(0, 0, 0); if (orderActor == None) Goto('Done'); Follow: if (IsOverlapping(orderActor)) Goto('Done'); MoveTarget = GetNextWaypoint(orderActor); if ((MoveTarget != None) && (!MoveTarget.Region.Zone.bWaterZone) && (MoveTarget.Physics != PHYS_Falling)) { if ((MoveTarget == orderActor) && MoveTarget.IsA('Pawn')) { if (GetNextVector(orderActor, useLoc)) { if (ShouldPlayWalk(useLoc)) PlayWalking(); MoveTo(useLoc, GetWalkingSpeed()); CheckDestLoc(useLoc); } else Goto('Pause'); } else { if (ShouldPlayWalk(MoveTarget.Location)) PlayWalking(); MoveToward(MoveTarget, GetWalkingSpeed()); CheckDestLoc(MoveTarget.Location, true); } if (IsOverlapping(orderActor)) Goto('Done'); else Goto('Follow'); } Pause: Acceleration = vect(0, 0, 0); TurnToward(orderActor); PlayWaiting(); Sleep(1.0); Goto('Follow'); Done: if (orderActor.IsA('PatrolPoint')) TurnTo(Location + PatrolPoint(orderActor).lookdir); GotoState('Standing'); ContinueGo: ContinueFromDoor: PlayWalking(); Goto('Follow'); } // ---------------------------------------------------------------------- // state RunningTo // // Move to an actor really fast. // ---------------------------------------------------------------------- state RunningTo { function SetFall() { StartFalling('RunningTo', 'ContinueRun'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function Bump(actor bumper) { // If we hit the guy we're going to, end the state if (bumper == OrderActor) GotoState('RunningTo', 'Done'); // Handle conversations, if need be Global.Bump(bumper); } function Touch(actor toucher) { // If we hit the guy we're going to, end the state if (toucher == OrderActor) GotoState('RunningTo', 'Done'); // Handle conversations, if need be Global.Touch(toucher); } function BeginState() { StandUp(); //BlockReactions(); SetupWeapon(false); SetDistress(false); bStasis = False; SeekPawn = None; EnableCheckDestLoc(true); } function EndState() { EnableCheckDestLoc(false); //ResetReactions(); bStasis = True; } Begin: Acceleration = vect(0, 0, 0); if (orderActor == None) Goto('Done'); Follow: if (IsOverlapping(orderActor)) Goto('Done'); MoveTarget = GetNextWaypoint(orderActor); if ((MoveTarget != None) && (!MoveTarget.Region.Zone.bWaterZone) && (MoveTarget.Physics != PHYS_Falling)) { if ((MoveTarget == orderActor) && MoveTarget.IsA('Pawn')) { if (GetNextVector(orderActor, useLoc)) { if (ShouldPlayWalk(useLoc)) PlayRunning(); MoveTo(useLoc, MaxDesiredSpeed); CheckDestLoc(useLoc); } else Goto('Pause'); } else { if (ShouldPlayWalk(MoveTarget.Location)) PlayRunning(); MoveToward(MoveTarget, MaxDesiredSpeed); CheckDestLoc(MoveTarget.Location, true); } if (IsOverlapping(orderActor)) Goto('Done'); else Goto('Follow'); } Pause: Acceleration = vect(0, 0, 0); TurnToward(orderActor); PlayWaiting(); Sleep(1.0); Goto('Follow'); Done: if (orderActor.IsA('PatrolPoint')) TurnTo(Location + PatrolPoint(orderActor).lookdir); GotoState('Standing'); ContinueRun: ContinueFromDoor: PlayRunning(); Goto('Follow'); } // ---------------------------------------------------------------------- // state DebugFollowing // // Following state used for pathnode testing // ---------------------------------------------------------------------- state DebugFollowing { function SetFall() { StartFalling('DebugFollowing', 'ContinueRun'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function BeginState() { StandUp(); BlockReactions(); SetupWeapon(false); SetDistress(false); bStasis = false; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); ResetReactions(); bStasis = true; } Begin: Acceleration = vect(0, 0, 0); if (orderActor == None) Goto('Done'); Follow: MoveTarget = GetNextWaypoint(orderActor); if (MoveTarget != None) { if (ShouldPlayWalk(MoveTarget.Location)) PlayRunning(); MoveToward(MoveTarget, 1.0); Goto('Follow'); } Pause: Acceleration = vect(0, 0, 0); TurnToward(orderActor); PlayWaiting(); Sleep(1.0); Goto('Follow'); Done: if (HasNextState()) GotoNextState(); else GotoState('Standing'); ContinueRun: ContinueFromDoor: PlayRunning(); Goto('Follow'); } // ---------------------------------------------------------------------- // state DebugPathfinding // // Following state used for pathnode testing // ---------------------------------------------------------------------- state DebugPathfinding { function SetFall() { StartFalling('DebugPathfinding', 'ContinueRun'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function BeginState() { StandUp(); BlockReactions(); SetupWeapon(false); SetDistress(false); bStasis = false; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); ResetReactions(); bStasis = true; } Begin: Acceleration = vect(0, 0, 0); if (orderActor == None) Goto('Done'); Follow: MoveTarget = FindPathToward(orderActor); if (MoveTarget != None) { if (ShouldPlayWalk(MoveTarget.Location)) PlayRunning(); MoveToward(MoveTarget, 1.0); Goto('Follow'); } Pause: Acceleration = vect(0, 0, 0); TurnToward(orderActor); PlayWaiting(); Sleep(1.0); Goto('Follow'); Done: if (HasNextState()) GotoNextState(); else GotoState('Standing'); ContinueRun: ContinueFromDoor: PlayRunning(); Goto('Follow'); } // ---------------------------------------------------------------------- // state Burning // // Whoa-oh-oh, I'm on fire. // ---------------------------------------------------------------------- state Burning { function ReactToInjury(Pawn instigatedBy, Name damageType, EHitLocation hitPos) { local name newLabel; if (health > 0) { if (enemy != instigatedBy) { SetEnemy(instigatedBy); newLabel = 'NewEnemy'; } else newLabel = 'ContinueBurn'; if ( Enemy != None ) LastSeenPos = Enemy.Location; SetNextState('Burning', newLabel); if ((damageType != 'TearGas') && (damageType != 'HalonGas') && (damageType != 'Stunned')) GotoDisabledState(damageType, hitPos); } } function SetFall() { StartFalling('Burning', 'ContinueBurn'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function PickDestination() { local float magnitude; local float distribution; local int yaw, pitch; local Rotator rotator1; local NavigationPoint nav; local float dist; local NavigationPoint bestNav; local float bestDist; destPoint = None; bestNav = None; bestDist = 2000; // max distance to water // Seek out water if (bCanSwim) { nav = Level.NavigationPointList; while (nav != None) { if (nav.Region.Zone.bWaterZone) { dist = VSize(Location - nav.Location); if (dist < bestDist) { bestNav = nav; bestDist = dist; } } nav = nav.nextNavigationPoint; } } if (bestNav != None) { // It'd be nice if we could traverse all pathnodes and figure out their // distances... unfortunately, it's too slow. :( MoveTarget = FindPathToward(bestNav); if (MoveTarget != None) { destPoint = bestNav; destLoc = bestNav.Location; } } // Can't get to water -- run willy-nilly if (destPoint == None) { if (Enemy == None) { yaw = 0; pitch = 0; distribution = 0; } else { rotator1 = Rotator(Location-Enemy.Location); yaw = rotator1.Yaw; pitch = rotator1.Pitch; distribution = 0.5; } magnitude = 300*(FRand()*0.4+0.8); // 400, +/-20% if (!AIPickRandomDestination(100, magnitude, yaw, distribution, pitch, distribution, 4, FRand()*0.4+0.35, destLoc)) destLoc = Location+(VRand()*200); // we give up } } function BeginState() { StandUp(); BlockReactions(); bCanConverse = False; SetupWeapon(false, true); bStasis = False; SetDistress(true); EnemyLastSeen = 0; SeekPawn = None; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); ResetReactions(); bCanConverse = True; bStasis = True; } Begin: if (!bOnFire) Goto('Done'); PlayOnFireSound(); NewEnemy: Acceleration = vect(0, 0, 0); Run: if (!bOnFire) Goto('Done'); PlayPanicRunning(); PickDestination(); if (destPoint != None) { MoveToward(MoveTarget, MaxDesiredSpeed); while ((MoveTarget != None) && (MoveTarget != destPoint)) { MoveTarget = FindPathToward(destPoint); if (MoveTarget != None) MoveToward(MoveTarget, MaxDesiredSpeed); } } else MoveTo(destLoc, MaxDesiredSpeed); Goto('Run'); Done: if (IsValidEnemy(Enemy)) HandleEnemy(); else FollowOrders(); ContinueBurn: ContinueFromDoor: Goto('Run'); } // ---------------------------------------------------------------------- // state AvoidingProjectiles // // Run away from a projectile. // ---------------------------------------------------------------------- state AvoidingProjectiles { ignores EnemyNotVisible; function SetFall() { StartFalling('RunningTo', 'ContinueRun'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function AnimEnd() { PlayWaiting(); } function PickDestination(bool bGotoWatch) { local NearbyProjectileList projList; local bool bMove; local vector projVector; local rotator projRot; local int i; local int bestSlot; local float bestDist; destLoc = vect(0,0,0); destPoint = None; bMove = false; if (GetProjectileList(projList, Location) > 0) { if (IsLocationDangerous(projList, Location)) { projVector = ComputeAwayVector(projList); projRot = Rotator(projVector); if (AIDirectionReachable(Location, projRot.Yaw, projRot.Pitch, CollisionRadius+24, VSize(projVector), destLoc)) { useLoc = Location + vect(0,0,1)*BaseEyeHeight; // hack bMove = true; } } } if (bMove) GotoState('AvoidingProjectiles', 'RunAway'); else if (bGotoWatch) GotoState('AvoidingProjectiles', 'Watch'); } function BeginState() { StandUp(); Disable('AnimEnd'); bCanJump = false; SetReactions(true, true, true, true, false, true, true, true, true, true, true, true); bStasis = False; useLoc = Location + vect(0,0,1)*BaseEyeHeight + Vector(Rotation); bCanConverse = False; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); if (JumpZ > 0) bCanJump = true; ResetReactions(); bStasis = True; bCanConverse = True; } Begin: Acceleration = vect(0,0,0); PickDestination(true); RunAway: PlayTurnHead(LOOK_Forward, 1.0, 0.0001); if (ShouldPlayWalk(destLoc)) PlayRunning(); MoveTo(destLoc, MaxDesiredSpeed); PickDestination(true); Watch: Acceleration = vect(0,0,0); PlayWaiting(); LookAtVector(useLoc, true, false, true); TurnTo(Vector(DesiredRotation)*1000+Location); sleepTime = 3.0; while (sleepTime > 0) { sleepTime -= 0.5; Sleep(0.5); PickDestination(false); } Done: if (Orders != 'AvoidingProjectiles') FollowOrders(); else GotoState('Wandering'); ContinueRun: ContinueFromDoor: PickDestination(false); Goto('Done'); } // ---------------------------------------------------------------------- // state AvoidingPawn // // Run away from an onrushing pawn (used for small, dumb critters only). // ---------------------------------------------------------------------- state AvoidingPawn { ignores EnemyNotVisible; function SetFall() { StartFalling('AvoidingPawn', 'ContinueAvoid'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function PickDestination() { local int iterations; local float magnitude; local rotator rot; local float speed; local float time; local vector newPos; local float minDist; minDist = 20; speed = VSize(Enemy.Velocity); if (speed == 0) time = 1; else time = VSize(Location - Enemy.Location)/speed; newPos = Enemy.Location + Enemy.Velocity*(time*0.98); magnitude = 100*(FRand()*0.2+0.9); // 120, +/-10% rot = Rotator(Location-newPos); iterations = 2; if (!AIDirectionReachable(Location, rot.Yaw, rot.Pitch, minDist, magnitude, destLoc)) { rot = Rotator(Location - Enemy.Location); if (!AIDirectionReachable(Location, rot.Yaw, rot.Pitch, minDist, magnitude, destLoc)) { if (speed > 0) rot = Rotator(Enemy.Velocity); else rot = Enemy.Rotation; if (!AIDirectionReachable(Location, rot.Yaw, rot.Pitch, minDist, magnitude, destLoc)) { rot.Yaw = -rot.Yaw; rot.Pitch = -rot.Pitch; if (!AIDirectionReachable(Location, rot.Yaw, rot.Pitch, minDist, magnitude, destLoc)) destLoc = Location; // we give up } } } } function BeginState() { StandUp(); bCanJump = false; bStasis = False; SetupWeapon(false); SetDistress(false); SeekPawn = None; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); bAcceptBump = True; if (JumpZ > 0) bCanJump = true; bStasis = True; } Begin: if (!ShouldBeStartled(Enemy)) Goto('Done'); Goto('Avoid'); ContinueFromDoor: Goto('Avoid'); Avoid: ContinueAvoid: if (!ShouldBeStartled(Enemy)) Goto('Done'); PickDestination(); if (destLoc == Location) Goto('Pause'); if (ShouldPlayWalk(destLoc)) PlayRunning(); MoveTo(destLoc, MaxDesiredSpeed); Goto('Avoid'); Pause: PlayWaiting(); Sleep(0.0); Goto('Avoid'); Done: if (Orders != 'AvoidingPawn') FollowOrders(); else GotoState('Wandering'); } // ---------------------------------------------------------------------- // state BackingOff // // Hack state used to back off when the NPC gets stuck. // ---------------------------------------------------------------------- state BackingOff { ignores EnemyNotVisible; function SetFall() { StartFalling('BackingOff', 'ContinueRun'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); CheckOpenDoor(HitNormal, Wall); } function bool PickDestination() { local bool bSuccess; local float magnitude; local rotator rot; magnitude = 300; rot = Rotator(Destination-Location); bSuccess = AIPickRandomDestination(64, magnitude, rot.Yaw+32768, 0.8, -rot.Pitch, 0.8, 3, 0.9, useLoc); return bSuccess; } function bool HandleTurn(Actor Other) { GotoState('BackingOff', 'Pause'); return false; } function BeginState() { StandUp(); BlockReactions(); bStasis = False; bInTransientState = True; EnableCheckDestLoc(false); bCanJump = false; } function EndState() { EnableCheckDestLoc(false); if (JumpZ > 0) bCanJump = true; ResetReactions(); bStasis = True; bInTransientState = false; } Begin: useRot = Rotation; if (!PickDestination()) Goto('Pause'); Acceleration = vect(0,0,0); MoveAway: if (ShouldPlayWalk(useLoc)) PlayRunning(); MoveTo(useLoc, MaxDesiredSpeed); Pause: Acceleration = vect(0,0,0); PlayWaiting(); Sleep(FRand()*2+2); Done: if (HasNextState()) GotoNextState(); else FollowOrders(); // THIS IS BAD!!! ContinueRun: ContinueFromDoor: Goto('Done'); } // ---------------------------------------------------------------------- // state OpeningDoor // // Open a door. // ---------------------------------------------------------------------- state OpeningDoor { ignores EnemyNotVisible; function SetFall() { StartFalling(NextState, NextLabel); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Global.HitWall(HitNormal, Wall); if (Target == Wall) CheckOpenDoor(HitNormal, Wall); } function bool DoorEncroaches() { local bool bEncroaches; local DeusExMover dxMover; bEncroaches = true; dxMover = DeusExMover(Target); if (dxMover != None) { if (IsDoor(dxMover) && (dxMover.MoverEncroachType == ME_IgnoreWhenEncroach)) bEncroaches = false; } return bEncroaches; } function FindBackupPoint() { local vector hitNorm; local rotator rot; local vector center; local vector area; local vector relPos; local float distX, distY; local float dist; hitNorm = Normal(destLoc); rot = Rotator(hitNorm); DeusExMover(Target).ComputeMovementArea(center, area); area.X += CollisionRadius + 30; area.Y += CollisionRadius + 30; //area.Z += CollisionHeight + 30; relPos = Location - center; if ((relPos.X < area.X) && (relPos.X > -area.X) && (relPos.Y < area.Y) && (relPos.Y > -area.Y)) { // hack if (hitNorm.Y == 0) hitNorm.Y = 0.00000001; if (hitNorm.X == 0) hitNorm.X = 0.00000001; if (hitNorm.X > 0) distX = (area.X - relPos.X)/hitNorm.X; else distX = (-area.X - relPos.X)/hitNorm.X; if (hitNorm.Y > 0) distY = (area.Y - relPos.Y)/hitNorm.Y; else distY = (-area.Y - relPos.Y)/hitNorm.Y; dist = FMin(distX, distY); if (dist < 45) dist = 45; else if (dist > 700) dist = 700; // sanity check if (!AIDirectionReachable(Location, rot.Yaw, rot.Pitch, 40, dist, destLoc)) destLoc = Location; } else destLoc = Location; } function vector FocusDirection() { return (Vector(Rotation)*30+Location); } function StopWaiting() { GotoState('OpeningDoor', 'DoorOpened'); } function AnimEnd() { PlayWaiting(); } function BeginState() { StandUp(); Disable('AnimEnd'); bCanJump = false; BlockReactions(); bStasis = False; bInTransientState = True; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); bAcceptBump = True; if (JumpZ > 0) bCanJump = true; ResetReactions(); bStasis = True; bInTransientState = false; } Begin: destLoc = vect(0,0,0); BeginHitNormal: Acceleration = vect(0,0,0); FindBackupPoint(); if (!DoorEncroaches()) if (!FrobDoor(Target)) Goto('DoorOpened'); PlayRunning(); StrafeTo(destLoc, FocusDirection()); if (DoorEncroaches()) if (!FrobDoor(Target)) Goto('DoorOpened'); PlayWaiting(); Sleep(5.0); DoorOpened: if (HasNextState()) GotoNextState(); else FollowOrders(); // THIS IS BAD!!! } // ---------------------------------------------------------------------- // state TakingHit // // React to a hit. // ---------------------------------------------------------------------- state TakingHit { ignores seeplayer, hearnoise, bump, hitwall, reacttoinjury; function TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { TakeDamageBase(Damage, instigatedBy, hitlocation, momentum, damageType, false); } function Landed(vector HitNormal) { if (Velocity.Z < -1.4 * JumpZ) MakeNoise(-0.5 * Velocity.Z/(FMax(JumpZ, 150.0))); bJustLanded = true; } function BeginState() { StandUp(); LastPainTime = Level.TimeSeconds; LastPainAnim = AnimSequence; bInterruptState = false; BlockReactions(); bCanConverse = False; bStasis = False; SetDistress(true); TakeHitTimer = 2.0; EnemyReadiness = 1.0; ReactionLevel = 1.0; bInTransientState = true; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); bInterruptState = true; ResetReactions(); bCanConverse = True; bStasis = True; bInTransientState = false; } Begin: Acceleration = vect(0, 0, 0); FinishAnim(); if ( (Physics == PHYS_Falling) && !Region.Zone.bWaterZone ) { Acceleration = vect(0,0,0); GotoState('FallingState', 'Ducking'); } else if (HasNextState()) GotoNextState(); else GotoState('Wandering'); } // ---------------------------------------------------------------------- // state RubbingEyes // // React to evil things like pepper spray. // ---------------------------------------------------------------------- state RubbingEyes { ignores seeplayer, hearnoise, bump, hitwall; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { TakeDamageBase(Damage, instigatedBy, hitlocation, momentum, damageType, false); } function ReactToInjury(Pawn instigatedBy, Name damageType, EHitLocation hitPos) { if ((damageType != 'TearGas') && (damageType != 'HalonGas') && (damageType != 'Stunned')) Global.ReactToInjury(instigatedBy, damageType, hitPos); } function SetFall() { StartFalling(NextState, NextLabel); } function AnimEnd() { PlayWaiting(); } function BeginState() { StandUp(); Disable('AnimEnd'); // LastPainTime = Level.TimeSeconds; // LastPainAnim = AnimSequence; bInterruptState = false; BlockReactions(); bCanConverse = False; bStasis = False; SetupWeapon(false, true); SetDistress(true); bStunned = True; bInTransientState = true; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); bInterruptState = true; ResetReactions(); bCanConverse = True; bStasis = True; if (Health > 0) bStunned = False; bInTransientState = false; } Begin: Acceleration = vect(0, 0, 0); PlayTearGasSound(); RubEyes: PlayRubbingEyesStart(); FinishAnim(); PlayRubbingEyes(); Sleep(15); PlayRubbingEyesEnd(); FinishAnim(); if (HasNextState()) GotoNextState(); else GotoState('Wandering'); } // ---------------------------------------------------------------------- // state Stunned // // React to being stunned. // ---------------------------------------------------------------------- state Stunned { ignores seeplayer, hearnoise, bump, hitwall; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { TakeDamageBase(Damage, instigatedBy, hitlocation, momentum, damageType, false); } function ReactToInjury(Pawn instigatedBy, Name damageType, EHitLocation hitPos) { if ((damageType != 'TearGas') && (damageType != 'HalonGas') && (damageType != 'Stunned')) Global.ReactToInjury(instigatedBy, damageType, hitPos); } function SetFall() { StartFalling(NextState, NextLabel); } function AnimEnd() { PlayWaiting(); } function BeginState() { StandUp(); Disable('AnimEnd'); bInterruptState = false; BlockReactions(); bCanConverse = False; bStasis = False; SetupWeapon(false); SetDistress(true); bStunned = True; bInTransientState = true; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); bInterruptState = true; ResetReactions(); bCanConverse = True; bStasis = True; // if we're dead, don't reset the flag if (Health > 0) bStunned = False; bInTransientState = false; } Begin: Acceleration = vect(0, 0, 0); PlayStunned(); Sleep(15); if (HasNextState()) GotoNextState(); else GotoState('Wandering'); } // ---------------------------------------------------------------------- // state Dying // // Why does the Unreal Dying state suck? // ---------------------------------------------------------------------- state Dying { ignores SeePlayer, EnemyNotVisible, HearNoise, KilledBy, Trigger, Bump, HitWall, HeadZoneChange, FootZoneChange, ZoneChange, Falling, WarnTarget, Died, Timer, TakeDamage; event Landed(vector HitNormal) { SetPhysics(PHYS_Walking); } function Tick(float deltaSeconds) { Global.Tick(deltaSeconds); if (DeathTimer > 0) { DeathTimer -= deltaSeconds; if ((DeathTimer <= 0) && (Physics == PHYS_Walking)) Acceleration = vect(0,0,0); } } function MoveFallingBody() { local Vector moveDir; local float totalTime; local float speed; local float stopTime; local int numFrames; if ((AnimRate > 0) && !IsA('Robot')) { totalTime = 1.0/AnimRate; // determine how long the anim lasts numFrames = int((1.0/(1.0-AnimLast))+0.1); // count frames (hack) // defaults moveDir = vect(0,0,0); stopTime = 0.01; ComputeFallDirection(totalTime, numFrames, moveDir, stopTime); speed = VSize(moveDir)/stopTime; // compute speed // Set variables necessary for movement when walking if (moveDir == vect(0,0,0)) Acceleration = vect(0,0,0); else Acceleration = Normal(moveDir)*AccelRate; GroundSpeed = speed; DesiredSpeed = 1.0; bIsWalking = false; DeathTimer = stopTime; } else Acceleration = vect(0,0,0); } function BeginState() { EnableCheckDestLoc(false); StandUp(); // don't do that stupid timer thing in Pawn.uc AIClearEventCallback('Futz'); AIClearEventCallback('MegaFutz'); AIClearEventCallback('Player'); AIClearEventCallback('WeaponDrawn'); AIClearEventCallback('LoudNoise'); AIClearEventCallback('WeaponFire'); AIClearEventCallback('Carcass'); AIClearEventCallback('Distress'); bInterruptState = false; BlockReactions(true); bCanConverse = False; bStasis = False; SetDistress(true); DeathTimer = 0; } Begin: WaitForLanding(); MoveFallingBody(); DesiredRotation.Pitch = 0; DesiredRotation.Roll = 0; // if we don't gib, then wait for the animation to finish if ((Health > -100) && !IsA('Robot')) FinishAnim(); SetWeapon(None); bHidden = True; Acceleration = vect(0,0,0); SpawnCarcass(); Destroy(); } // ---------------------------------------------------------------------- // state FallingState // // Fall! // ---------------------------------------------------------------------- state FallingState { ignores Bump, Hitwall, WarnTarget, ReactToInjury; function ZoneChange(ZoneInfo newZone) { Global.ZoneChange(newZone); if (newZone.bWaterZone) GotoState('FallingState', 'Splash'); } //choose a jump velocity function AdjustJump() { local float velZ; local vector FullVel; velZ = Velocity.Z; FullVel = Normal(Velocity) * GroundSpeed; If (Location.Z > Destination.Z + CollisionHeight + 2 * MaxStepHeight) { Velocity = FullVel; Velocity.Z = velZ; Velocity = EAdjustJump(); Velocity.Z = 0; if ( VSize(Velocity) < 0.9 * GroundSpeed ) { Velocity.Z = velZ; return; } } Velocity = FullVel; Velocity.Z = JumpZ + velZ; Velocity = EAdjustJump(); } singular function BaseChange() { local float minJumpZ; Global.BaseChange(); if (Physics == PHYS_Walking) { minJumpZ = FMax(JumpZ, 150.0); bJustLanded = true; if (Health > 0) { if ((Velocity.Z < -0.8 * minJumpZ) || bUpAndOut) GotoState('FallingState', 'Landed'); else if (Velocity.Z < -0.8 * JumpZ) GotoState('FallingState', 'FastLanded'); else GotoState('FallingState', 'Done'); } } } function Landed(vector HitNormal) { local float landVol, minJumpZ; local vector legLocation; minJumpZ = FMax(JumpZ, 150.0); if ( (Velocity.Z < -0.8 * minJumpZ) || bUpAndOut) { PlayLanded(Velocity.Z); if (Velocity.Z < -700) { legLocation = Location + vect(-1,0,-1); // damage left leg TakeDamage(-0.14 * (Velocity.Z + 700), Self, legLocation, vect(0,0,0), 'fell'); legLocation = Location + vect(1,0,-1); // damage right leg TakeDamage(-0.14 * (Velocity.Z + 700), Self, legLocation, vect(0,0,0), 'fell'); legLocation = Location + vect(0,0,1); // damage torso TakeDamage(-0.04 * (Velocity.Z + 700), Self, legLocation, vect(0,0,0), 'fell'); } landVol = Velocity.Z/JumpZ; landVol = 0.005 * Mass * FMin(5, landVol * landVol); if ( !FootRegion.Zone.bWaterZone ) PlaySound(Land, SLOT_Interact, FMin(20, landVol)); } else if ( Velocity.Z < -0.8 * JumpZ ) PlayLanded(Velocity.Z); } function SetFall() { if (!bUpAndOut) GotoState('FallingState'); } function BeginState() { StandUp(); if (Enemy == None) Disable('EnemyNotVisible'); else { Disable('HearNoise'); Disable('SeePlayer'); } bInterruptState = false; bCanConverse = False; bStasis = False; bInTransientState = true; EnableCheckDestLoc(false); } function EndState() { EnableCheckDestLoc(false); bUpAndOut = false; bInterruptState = true; bCanConverse = True; bStasis = True; bInTransientState = false; } LongFall: if ( bCanFly ) { SetPhysics(PHYS_Flying); Goto('Done'); } Sleep(0.7); PlayFalling(); if ( Velocity.Z > -150 ) //stuck { SetPhysics(PHYS_Falling); if ( Enemy != None ) Velocity = groundspeed * normal(Enemy.Location - Location); else Velocity = groundspeed * VRand(); Velocity.Z = FMax(JumpZ, 250); } Goto('LongFall'); FastLanded: FinishAnim(); TweenToWaiting(0.15); Goto('Done'); Landed: if ( !bIsPlayer ) //bots act like players Acceleration = vect(0,0,0); FinishAnim(); TweenToWaiting(0.2); if ( !bIsPlayer ) Sleep(0.08); Done: bUpAndOut = false; if (HasNextState()) GotoNextState(); else GotoState('Wandering'); Splash: bUpAndOut = false; FinishAnim(); if (HasNextState()) GotoNextState(); else GotoState('Wandering'); Begin: if (Enemy == None) Disable('EnemyNotVisible'); else { Disable('HearNoise'); Disable('SeePlayer'); } if (bUpAndOut) //water jump { if ( !bIsPlayer ) { DesiredRotation = Rotation; DesiredRotation.Pitch = 0; Velocity.Z = 440; } } else { if (Region.Zone.bWaterZone) { SetPhysics(PHYS_Swimming); GotoNextState(); } if ( !bJumpOffPawn ) AdjustJump(); else bJumpOffPawn = false; PlayFall: PlayFalling(); FinishAnim(); } if (Physics != PHYS_Falling) Goto('Done'); Sleep(2.0); Goto('LongFall'); Ducking: } // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // OBSOLETE // ---------------------------------------------------------------------- function PlayHit(float Damage, vector HitLocation, name damageType, vector Momentum) { log("ERROR - PlayHit should not be called!"); } function PlayHitAnim(vector HitLocation, float Damage) { log("ERROR - PlayHitAnim should not be called!"); } function PlayDeathHit(float Damage, vector HitLocation, name damageType, vector Momentum) { log("ERROR - PlayDeathHit should not be called!"); } function PlayChallenge() { log("ERROR - PlayChallenge should not be called!"); } function JumpOffPawn() { /* Velocity += (60 + CollisionRadius) * VRand(); Velocity.Z = 180 + CollisionHeight; SetPhysics(PHYS_Falling); bJumpOffPawn = true; SetFall(); */ //log("ERROR - JumpOffPawn should not be called!"); } // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- defaultproperties { Restlessness=0.500000 Wanderlust=0.500000 Cowardice=0.500000 maxRange=4000.000000 MinHealth=30.000000 RandomWandering=1.000000 bAlliancesChanged=True Orders=Wandering HomeExtent=800.000000 WalkingSpeed=0.400000 bCanBleed=True ClotPeriod=30.000000 bShowPain=True bCanSit=True bLikesNeutral=True bUseFirstSeatOnly=True bCanConverse=True bAvoidAim=True AvoidAccuracy=0.400000 bAvoidHarm=True HarmAccuracy=0.800000 CloseCombatMult=0.300000 bHateShot=True bHateInjury=True bReactPresence=True bReactProjectiles=True bEmitDistress=True RaiseAlarm=RAISEALARM_BeforeFleeing bMustFaceTarget=True FireAngle=360.000000 MaxProvocations=1 AgitationSustainTime=30.000000 AgitationDecayRate=0.050000 FearSustainTime=25.000000 FearDecayRate=0.500000 SurprisePeriod=2.000000 SightPercentage=0.500000 bHasShadow=True ShadowScale=1.000000 BaseAssHeight=-26.000000 EnemyTimeout=4.000000 bTickVisibleOnly=True bInWorld=True bHighlight=True bHokeyPokey=True InitialInventory(0)=(Count=1) InitialInventory(1)=(Count=1) InitialInventory(2)=(Count=1) InitialInventory(3)=(Count=1) InitialInventory(4)=(Count=1) InitialInventory(5)=(Count=1) InitialInventory(6)=(Count=1) InitialInventory(7)=(Count=1) bSpawnBubbles=True bWalkAround=True BurnPeriod=30.000000 DistressTimer=-1.000000 CloakThreshold=50 walkAnimMult=0.700000 runAnimMult=1.000000 bCanStrafe=True bCanWalk=True bCanSwim=True bCanOpenDoors=True bIsHuman=True bCanGlide=False AirSpeed=320.000000 AccelRate=200.000000 JumpZ=120.000000 MinHitWall=9999999827968.000000 HearingThreshold=0.150000 Skill=2.000000 AIHorizontalFov=160.000000 AspectRatio=2.300000 bForceStasis=True BindName="ScriptedPawn" FamiliarName="DEFAULT FAMILIAR NAME - REPORT THIS AS A BUG" UnfamiliarName="DEFAULT UNFAMILIAR NAME - REPORT THIS AS A BUG" } |
Overview | Package | Class | Source | Class tree | Glossary | Deus Ex UnrealScript Documentation |
previous class next class | frames no frames |