Overview Package Class Source Class tree Glossary
previous class      next class frames      no frames

DeusEx.DeusExPlayer


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
//=============================================================================
// DeusExPlayer.
//=============================================================================
class DeusExPlayer extends PlayerPawnExt
    native;

#exec OBJ LOAD FILE=Effects

// Name and skin assigned to PC by player on the Character Generation screen
var travel String   TruePlayerName;
var travel int      PlayerSkin;

// Combat Difficulty, set only at new game time
var travel Float CombatDifficulty;

// Augmentation system vars
var travel AugmentationManager AugmentationSystem;

// Skill system vars
var travel SkillManager SkillSystem;

var() travel int SkillPointsTotal;
var() travel int SkillPointsAvail;

// Credits (money) the player has
var travel int Credits;

// Energy the player has
var travel float Energy;
var travel float EnergyMax;
var travel float EnergyDrain;               // amount of energy left to drain
var travel float EnergyDrainTotal;      // total amount of energy to drain
var float MaxRegenPoint;     // in multiplayer, the highest that auto regen will take you
var float RegenRate;         // the number of points healed per second in mp

// Keyring, used to store any keys the player picks up
var travel NanoKeyRing KeyRing;     // Inventory Item
var travel NanoKeyInfo KeyList;     // List of Keys

// frob vars
var() float MaxFrobDistance;
var Actor FrobTarget;
var float FrobTime;

// HUD Refresh Timer
var float LastRefreshTime; 

// Conversation System Vars
var ConPlay conPlay;                        // Conversation
var DataLinkPlay dataLinkPlay;              // Used for DataLinks
var travel ConHistory conHistory;           // Conversation History

// Inventory System Vars
var travel byte             invSlots[30];       // 5x6 grid of inventory slots
var int                     maxInvRows;         // Maximum number of inventory rows
var int                     maxInvCols;         // Maximum number of inventory columns
var travel Inventory        inHand;             // The current object in hand
var travel Inventory        inHandPending;      // The pending item waiting to be put in hand
var travel Inventory        ClientinHandPending; // Client temporary inhand pending, for mousewheel use.
var travel Inventory        LastinHand;         // Last object inhand, so we can detect inhand changes on the client.
var travel bool             bInHandTransition;  // The inHand is being swapped out
// DEUS_EX AMSD  Whether to ignore inv slots in multiplayer
var bool bBeltIsMPInventory;

// Goal Tracking
var travel DeusExGoal FirstGoal;    
var travel DeusExGoal LastGoal;

// Note Tracking
var travel DeusExNote FirstNote;
var travel DeusExNote LastNote;

// Data Vault Images
var travel DataVaultImage FirstImage;

// Log Messages
var DeusExLog FirstLog;
var DeusExLog LastLog;

// used by ViewModel
var Actor ViewModelActor[8];

// DEUS_EX AMSD For multiplayer option propagation UGH!
// In most cases options will sync on their own.  But for
// initial loadout based on options, we need to send them to the
// server.  Easiest thing to do is have a function at startup
// that sends that info.
var bool bFirstOptionsSynced;
var bool bSecondOptionsSynced;

// used while crouching
var travel bool bForceDuck;
var travel bool bCrouchOn;              // used by toggle crouch
var travel bool bWasCrouchOn;           // used by toggle crouch
var travel byte lastbDuck;              // used by toggle crouch

// leaning vars
var bool bCanLean;
var float curLeanDist;
var float prevLeanDist;

// toggle walk
var bool bToggleWalk;

// communicate run silent value in multiplayer
var float   RunSilentValue;

// cheats
var bool  bWarrenEMPField;
var float WarrenTimer;
var int   WarrenSlot;

// used by lots of stuff
var name FloorMaterial;
var name WallMaterial;
var Vector WallNormal;

// drug effects on the player
var float drugEffectTimer;

// shake variables
var float JoltMagnitude;  // magnitude of bounce imposed by heavy footsteps

// poison dart effects on the player
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

// bleeding variables
var     float       BleedRate;      // how profusely the player 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 float FlashTimer; // How long it should take the current flash to fade.

// length of time player can stay underwater
// modified by SkillSwimming, AugAqualung, and Rebreather
var float swimDuration;
var float swimTimer;
var float swimBubbleTimer;

// conversation info
var Actor ConversationActor;
var Actor lastThirdPersonConvoActor;
var float lastThirdPersonConvoTime;
var Actor lastFirstPersonConvoActor;
var float lastFirstPersonConvoTime;

var Bool bStartingNewGame;                          // Set to True when we're starting a new game. 
var Bool bSavingSkillsAugs;

// Put spy drone here instead of HUD
var bool bSpyDroneActive;
var int spyDroneLevel;
var float spyDroneLevelValue;
var SpyDrone aDrone;

// Buying skills for multiplayer
var bool        bBuySkills;

// If player wants to see a profile of the killer in multiplayer
var bool        bKillerProfile;

// Multiplayer notification messages
const           MPFLAG_FirstSpot                = 0x01;
const           MPSERVERFLAG_FirstPoison    = 0x01;
const           MPSERVERFLAG_FirstBurn      = 0x02;
const           MPSERVERFLAG_TurretInv      = 0x04;
const           MPSERVERFLAG_CameraInv      = 0x08;
const           MPSERVERFLAG_LostLegs       = 0x10;
const           MPSERVERFLAG_DropItem       = 0x20;
const           MPSERVERFLAG_NoCloakWeapon = 0x40;

const           mpMsgDelay = 4.0;

var int     mpMsgFlags;
var int     mpMsgServerFlags;

const   MPMSG_TeamUnatco        =0;
const   MPMSG_TeamNsf           =1;
const   MPMSG_TeamHit           =2;
const   MPMSG_TeamSpot          =3;
const   MPMSG_FirstPoison       =4;
const   MPMSG_FirstBurn     =5;
const   MPMSG_TurretInv     =6;
const   MPMSG_CameraInv     =7;
const   MPMSG_CloseKills        =8;
const   MPMSG_TimeNearEnd       =9;
const   MPMSG_LostLegs          =10;
const   MPMSG_DropItem          =11;
const MPMSG_KilledTeammate =12;
const MPMSG_TeamLAM         =13;
const MPMSG_TeamComputer    =14;
const MPMSG_NoCloakWeapon   =15;
const MPMSG_TeamHackTurret  =16;

var int         mpMsgCode;
var float       mpMsgTime;
var int         mpMsgOptionalParam;
var String      mpMsgOptionalString;

// Variables used when starting new game to show the intro first.
var String      strStartMap;
var travel Bool bStartNewGameAfterIntro;
var travel Bool bIgnoreNextShowMenu;

// map that we're about to travel to after we finish interpolating
var String NextMap;

// Configuration Variables
var globalconfig bool bObjectNames;                 // Object names on/off
var globalconfig bool bNPCHighlighting;             // NPC highlighting when new convos
var globalconfig bool bSubtitles;                   // True if Conversation Subtitles are on
var globalconfig bool bAlwaysRun;                   // True to default to running
var globalconfig bool bToggleCrouch;                // True to let key toggle crouch
var globalconfig float logTimeout;                  // Log Timeout Value
var globalconfig byte  maxLogLines;                 // Maximum number of log lines visible
var globalconfig bool bHelpMessages;                // Multiplayer help messages

// Overlay Options (TODO: Move to DeusExHUD.uc when serializable)
var globalconfig byte translucencyLevel;            // 0 - 10?
var globalconfig bool bObjectBeltVisible;
var globalconfig bool bHitDisplayVisible;
var globalconfig bool bAmmoDisplayVisible;
var globalconfig bool bAugDisplayVisible;   
var globalconfig bool bDisplayAmmoByClip;   
var globalconfig bool bCompassVisible;
var globalconfig bool bCrosshairVisible;
var globalconfig bool bAutoReload;
var globalconfig bool bDisplayAllGoals;
var globalconfig bool bHUDShowAllAugs;              // TRUE = Always show Augs on HUD
var globalconfig int  UIBackground;                 // 0 = Render 3D, 1 = Snapshot, 2 = Black
var globalconfig bool bDisplayCompletedGoals;
var globalconfig bool bShowAmmoDescriptions;
var globalconfig bool bConfirmSaveDeletes;
var globalconfig bool bConfirmNoteDeletes;
var globalconfig bool bAskedToTrain;

// Multiplayer Playerspecific options
var() globalconfig Name AugPrefs[9]; //List of aug preferences.

// Used to manage NPC Barks
var travel BarkManager barkManager;

// Color Theme Manager, used to manage all the pretty 
// colors the player gets to play with for the Menus
// and HUD windows.

var travel ColorThemeManager ThemeManager;
var globalconfig String MenuThemeName;
var globalconfig String HUDThemeName;

// Translucency settings for various UI Elements
var globalconfig Bool bHUDBordersVisible;
var globalconfig Bool bHUDBordersTranslucent;
var globalconfig Bool bHUDBackgroundTranslucent;
var globalconfig Bool bMenusTranslucent;

var localized String InventoryFull;
var localized String TooMuchAmmo;
var localized String TooHeavyToLift;
var localized String CannotLift;
var localized String NoRoomToLift;
var localized String CanCarryOnlyOne;
var localized String CannotDropHere;
var localized String HandsFull;
var localized String NoteAdded;
var localized String GoalAdded;
var localized String PrimaryGoalCompleted;
var localized String SecondaryGoalCompleted;
var localized String EnergyDepleted;
var localized String AddedNanoKey;
var localized String HealedPointsLabel;
var localized String HealedPointLabel;
var localized String SkillPointsAward;
var localized String QuickSaveGameTitle;
var localized String WeaponUnCloak;
var localized String TakenOverString;
var localized String    HeadString;
var localized String    TorsoString;
var localized String LegsString;
var localized String WithTheString;
var localized String WithString;
var localized String PoisonString;
var localized String BurnString;
var localized String NoneString;

var ShieldEffect DamageShield; //visual damage effect for multiplayer feedback
var float ShieldTimer; //for turning shield to fade.
enum EShieldStatus
{
   SS_Off,
   SS_Fade,
   SS_Strong
};

var EShieldStatus ShieldStatus;

var Pawn                    myBurner;
var Pawn                    myPoisoner;
var Actor               myProjKiller;
var Actor               myTurretKiller;
var Actor               myKiller;
var KillerProfile       killProfile;
var InvulnSphere        invulnSph;

// Conversation Invocation Methods
enum EInvokeMethod
{
    IM_Bump,
    IM_Frob,
    IM_Sight,
    IM_Radius,
    IM_Named,
    IM_Other
};

enum EMusicMode
{
    MUS_Ambient,
    MUS_Combat,
    MUS_Conversation,
    MUS_Outro,
    MUS_Dying
};

var EMusicMode musicMode;
var byte savedSection;      // last section playing before interrupt
var float musicCheckTimer;
var float musicChangeTimer;

// Used to keep track of # of saves
var travel int saveCount;
var travel Float saveTime;

// for getting at the debug system
var DebugInfo GlobalDebugObj;

// Set to TRUE if the player can see the quotes.  :)
var globalconfig bool bQuotesEnabled;

// DEUS_EX AMSD For propagating gametype
var GameInfo DXGame;
var float    ServerTimeDiff;
var float    ServerTimeLastRefresh;

// DEUS_EX AMSD For trying higher damage games
var float MPDamageMult;

// Nintendo immunity
var float   NintendoImmunityTime;
var float   NintendoImmunityTimeLeft;
var bool        bNintendoImmunity;
const           NintendoDelay = 6.0;

// For closing comptuers if the server quits
var Computers ActiveComputer;

// native Functions
native(1099) final function string GetDeusExVersion();
native(2100) final function ConBindEvents();
native(3001) final function name SetBoolFlagFromString(String flagNameString, bool bValue);
native(3002) final function ConHistory CreateHistoryObject();
native(3003) final function ConHistoryEvent CreateHistoryEvent();
native(3010) final function DeusExLog CreateLogObject();
native(3011) final function SaveGame(int saveIndex, optional String saveDesc);
native(3012) final function DeleteSaveGameFiles(optional String saveDirectory);
native(3013) final function GameDirectory CreateGameDirectoryObject();
native(3014) final function DataVaultImageNote CreateDataVaultImageNoteObject();
native(3015) final function DumpLocation CreateDumpLocationObject();
native(3016) final function UnloadTexture(Texture texture);
//native 3017 taken by particleiterator.

//
// network replication
//
replication
{
    // server to client
    reliable if ((Role == ROLE_Authority) && (bNetOwner))
        AugmentationSystem, SkillSystem, SkillPointsTotal, SkillPointsAvail, inHand, inHandPending, KeyRing, Energy, 
          bSpyDroneActive, DXGame, bBuySkills, drugEffectTimer, killProfile;

    reliable if (Role == ROLE_Authority)
       ShieldStatus, RunSilentValue, aDrone, NintendoImmunityTimeLeft;
    
    // client to server
    reliable if (Role < ROLE_Authority)
        BarkManager, FrobTarget, AugPrefs, bCanLean, curLeanDist, prevLeanDist, 
        bInHandTransition, bForceDuck, FloorMaterial, WallMaterial, WallNormal, swimTimer, swimDuration;

    // Functions the client can call
    reliable if (Role < ROLE_Authority)
        DoFrob, ParseLeftClick, ParseRightClick, ReloadWeapon, PlaceItemInSlot, RemoveItemFromSlot, ClearInventorySlots,
      SetInvSlots, FindInventorySlot, ActivateBelt, DropItem, SetInHand, AugAdd, ExtinguishFire, CatchFire,
      AllEnergy, ClearPosition, ClearBelt, AddObjectToBelt, RemoveObjectFromBelt, TeamSay,
      KeypadRunUntriggers, KeypadRunEvents, KeypadToggleLocks, ReceiveFirstOptionSync, ReceiveSecondOptionSync,CreateDrone, MoveDrone,
      CloseComputerScreen, SetComputerHackTime, UpdateCameraRotation, ToggleCameraState,
      SetTurretTrackMode, SetTurretState, NewMultiplayerMatch, PopHealth, ServerUpdateLean, BuySkills, PutInHand,
      MakeCameraAlly, PunishDetection, ServerSetAutoReload, FailRootWindowCheck, FailConsoleCheck, ClientPossessed;

   // Unreliable functions the client can call
   unreliable if (Role < ROLE_Authority)
      MaintainEnergy, UpdateTranslucency;

   // Functions the server calls in client
   reliable if ((Role == ROLE_Authority) && (bNetOwner))
      UpdateAugmentationDisplayStatus, AddAugmentationDisplay, RemoveAugmentationDisplay, ClearAugmentationDisplay, ShowHud,
        ActivateKeyPadWindow, SetDamagePercent, SetServerTimeDiff, ClientTurnOffScores;

   reliable if (Role == ROLE_Authority)
      InvokeComputerScreen, ClientDeath, AddChargedDisplay, RemoveChargedDisplay, MultiplayerDeathMsg, MultiplayerNotifyMsg, 
      BuySkillSound, ShowMultiplayerWin, ForceDroneOff ,AddDamageDisplay, ClientSpawnHits, CloseThisComputer, ClientPlayAnimation, ClientSpawnProjectile, LocalLog,
      VerifyRootWindow, VerifyConsole, ForceDisconnect;

}

// ----------------------------------------------------------------------
// PostBeginPlay()
//
// set up the augmentation and skill systems
// ----------------------------------------------------------------------

function PostBeginPlay()
{
    local DeusExLevelInfo info;
    local int levelInfoCount;

    Super.PostBeginPlay();

    // Check to make sure there's only *ONE* DeusExLevelInfo and 
    // go fucking *BOOM* if we find more than one.

    levelInfoCount = 0;
    foreach AllActors(class'DeusExLevelInfo', info)
        levelInfoCount++;

    Assert(levelInfoCount <= 1);
    
    // give us a shadow
   if (Level.Netmode == NM_Standalone)   
      CreateShadow();

    InitializeSubSystems();
   DXGame = Level.Game;
   ShieldStatus = SS_Off;
    ServerTimeLastRefresh = 0;

    // Safeguard so no cheats in multiplayer
    if ( Level.NetMode != NM_Standalone )
        bCheatsEnabled = False;
}

function ServerSetAutoReload( bool bAuto )
{
    bAutoReload = bAuto;
}

// ----------------------------------------------------------------------

function SetServerTimeDiff( float sTime )
{
    ServerTimeDiff = (sTime - Level.Timeseconds);
}

// ----------------------------------------------------------------------
// PostNetBeginPlay()
//
// Take care of the theme manager
// ----------------------------------------------------------------------

simulated function PostNetBeginPlay()
{
   Super.PostNetBeginPlay();

   if (Role == ROLE_SimulatedProxy)
   {
      DrawShield();
      CreatePlayerTracker();
        if ( NintendoImmunityTimeLeft > 0.0 )
            DrawInvulnShield();
      return;
   }

    //DEUS_EX AMSD In multiplayer, we need to do this for our local theme manager, since
    //PostBeginPlay isn't called to set these up, and the Thememanager can be local, it
    //doesn't have to sync with the server.
    if (ThemeManager == NONE)
    {
        CreateColorThemeManager();
        ThemeManager.SetOwner(self);
        ThemeManager.SetCurrentHUDColorTheme(ThemeManager.GetFirstTheme(1));        
        ThemeManager.SetCurrentMenuColorTheme(ThemeManager.GetFirstTheme(0)); 
        ThemeManager.SetMenuThemeByName(MenuThemeName);  
        ThemeManager.SetHUDThemeByName(HUDThemeName);
        if (DeusExRootWindow(rootWindow) != None)
           DeusExRootWindow(rootWindow).ChangeStyle();        
    }
    ReceiveFirstOptionSync(AugPrefs[0], AugPrefs[1], AugPrefs[2], AugPrefs[3], AugPrefs[4]);
    ReceiveSecondOptionSync(AugPrefs[5], AugPrefs[6], AugPrefs[7], AugPrefs[8]);
    ShieldStatus = SS_Off;
     bCheatsEnabled = False;

     ServerSetAutoReload( bAutoReload );
}

// ----------------------------------------------------------------------
// InitializeSubSystems()
// ----------------------------------------------------------------------

function InitializeSubSystems()
{
    // Spawn the BarkManager
    if (BarkManager == None)
        BarkManager = Spawn(class'BarkManager', Self);

    // Spawn the Color Manager
    CreateColorThemeManager();
    ThemeManager.SetOwner(self);

    // install the augmentation system if not found
    if (AugmentationSystem == None)
    {
        AugmentationSystem = Spawn(class'AugmentationManager', Self);
        AugmentationSystem.CreateAugmentations(Self);
        AugmentationSystem.AddDefaultAugmentations();        
        AugmentationSystem.SetOwner(Self);       
    }
    else
    {
        AugmentationSystem.SetPlayer(Self);
        AugmentationSystem.SetOwner(Self);
    }

    // install the skill system if not found
    if (SkillSystem == None)
    {
        SkillSystem = Spawn(class'SkillManager', Self);
        SkillSystem.CreateSkills(Self);
    }
    else
    {
        SkillSystem.SetPlayer(Self);
    }

   if ((Level.Netmode == NM_Standalone) || (!bBeltIsMPInventory))
   {
      // Give the player a keyring
      CreateKeyRing();
   }
}

// ----------------------------------------------------------------------
// PostPostBeginPlay()
// ----------------------------------------------------------------------

function PostPostBeginPlay()
{
    Super.PostPostBeginPlay();

    // Bind any conversation events to this DeusExPlayer
    ConBindEvents();

    // Restore colors that the user selected (as opposed to those
    // stored in the savegame)
    ThemeManager.SetMenuThemeByName(MenuThemeName);
    ThemeManager.SetHUDThemeByName(HUDThemeName);

    if ((Level.NetMode != NM_Standalone) && ( killProfile == None ))
        killProfile = Spawn(class'KillerProfile', Self);
}

// ----------------------------------------------------------------------
// PreTravel() - Called when a ClientTravel is about to happen
// ----------------------------------------------------------------------

function PreTravel()
{
    // Set a flag designating that we're traveling,
    // so MissionScript can check and not call FirstFrame() for this map.
    
    flagBase.SetBool('PlayerTraveling', True, True, 0);

    SaveSkillPoints();

    if (dataLinkPlay != None)
        dataLinkPlay.AbortAndSaveHistory();

    // If the player is burning (Fire! Fire!), extinguish him
    // before the map transition.  This is done to fix stuff 
    // that's fucked up.
    ExtinguishFire();
}

// ----------------------------------------------------------------------
// TravelPostAccept()
// ----------------------------------------------------------------------

event TravelPostAccept()
{
    local DeusExLevelInfo info;
    local MissionScript scr;
    local bool bScriptRunning;
    local InterpolationPoint I;

    Super.TravelPostAccept();

    // reset the keyboard
    ResetKeyboard();

    info = GetLevelInfo();

    if (info != None)
    {
        // hack for the DX.dx logo/splash level
        if (info.MissionNumber == -2)
        {
            foreach AllActors(class 'InterpolationPoint', I, 'IntroCam')
            {
                if (I.Position == 1)
                {
                    SetCollision(False, False, False);
                    bCollideWorld = False;
                    Target = I;
                    SetPhysics(PHYS_Interpolating);
                    PhysRate = 1.0;
                    PhysAlpha = 0.0;
                    bInterpolating = True;
                    bStasis = False;
                    ShowHud(False);
                    PutInHand(None);
                    GotoState('Interpolating');
                    break;
                }
            }
            return;
        }

        // hack for the DXOnly.dx splash level
        if (info.MissionNumber == -1)
        {
            ShowHud(False);
            GotoState('Paralyzed');
            return;
        }
    }

    // Restore colors
    if (ThemeManager != None)
    {
        ThemeManager.SetMenuThemeByName(MenuThemeName);
        ThemeManager.SetHUDThemeByName(HUDThemeName);
    }

    // Make sure any charged pickups that were active 
    // before travelling are still active.
    RefreshChargedPickups();

    // Make sure the Skills and Augmentation systems 
    // are properly initialized and reset.

    RestoreSkillPoints();

    if (SkillSystem != None)
    {
        SkillSystem.SetPlayer(Self);
    }

    if (AugmentationSystem != None)
    {
        // set the player correctly
        AugmentationSystem.SetPlayer(Self);
        AugmentationSystem.RefreshAugDisplay();
    }

    // Nuke any existing conversation
    if (conPlay != None)
        conPlay.TerminateConversation();

    // Make sure any objects that care abou the PlayerSkin
    // are notified
    UpdatePlayerSkin();

    // If the player was carrying a decoration, 
    // call TravelPostAccept() so it can initialize itself
    if (CarriedDecoration != None)
        CarriedDecoration.TravelPostAccept();

    // If the player was carrying a decoration, make sure
    // it's placed back in his hand (since the location
    // info won't properly travel)
    PutCarriedDecorationInHand();

    // Reset FOV
    SetFOVAngle(Default.DesiredFOV);

    // If the player had a scope view up, make sure it's 
    // properly restore
    RestoreScopeView();

    // make sure the mission script has been spawned correctly
    if (info != None)
    {
        bScriptRunning = False;
        foreach AllActors(class'MissionScript', scr)
            bScriptRunning = True;

        if (!bScriptRunning)
            info.SpawnScript();
    }

    // make sure the player's eye height is correct
    BaseEyeHeight = CollisionHeight - (GetDefaultCollisionHeight() - Default.BaseEyeHeight);
}

// ----------------------------------------------------------------------
// Update Time Played
// ----------------------------------------------------------------------

final function UpdateTimePlayed(float deltaTime)
{
    saveTime += deltaTime;
}

// ----------------------------------------------------------------------
// RestoreScopeView()
// ----------------------------------------------------------------------

function RestoreScopeView()
{
    if (inHand != None)
    {
        if (inHand.IsA('Binoculars') && (inHand.bActive))
            Binoculars(inHand).RefreshScopeDisplay(Self, True);
        else if ((DeusExWeapon(inHand) != None) && (DeusExWeapon(inHand).bZoomed))
            DeusExWeapon(inHand).RefreshScopeDisplay(Self, True, True);
    }
}

// ----------------------------------------------------------------------
// RefreshChargedPickups()
// ----------------------------------------------------------------------

function RefreshChargedPickups()
{
    local ChargedPickup anItem;

    // Loop through all the ChargedPicksups and look for charged pickups
    // that are active.  If we find one, add to the user-interface.

    foreach AllActors(class'ChargedPickup', anItem)
    {
        if ((anItem.Owner == Self) && (anItem.IsActive()))
        {
            // Make sure tech goggles display is refreshed
            if (anItem.IsA('TechGoggles'))
                TechGoggles(anItem).UpdateHUDDisplay(Self);

            AddChargedDisplay(anItem);
        }
    }
}

// ----------------------------------------------------------------------
// UpdatePlayerSkin()
// ----------------------------------------------------------------------

function UpdatePlayerSkin()
{
    local PaulDenton paul;
    local PaulDentonCarcass paulCarcass;
    local JCDentonMaleCarcass jcCarcass;
    local JCDouble jc;

    // Paul Denton
    foreach AllActors(class'PaulDenton', paul)
        break;

    if (paul != None)
        paul.SetSkin(Self);

    // Paul Denton Carcass
    foreach AllActors(class'PaulDentonCarcass', paulCarcass)
        break;

    if (paulCarcass != None)
        paulCarcass.SetSkin(Self);

    // JC Denton Carcass
    foreach AllActors(class'JCDentonMaleCarcass', jcCarcass)
        break;

    if (jcCarcass != None)
        jcCarcass.SetSkin(Self);

    // JC's stunt double
    foreach AllActors(class'JCDouble', jc)
        break;

    if (jc != None)
        jc.SetSkin(Self);
}


// ----------------------------------------------------------------------
// GetLevelInfo()
// ----------------------------------------------------------------------

function DeusExLevelInfo GetLevelInfo()
{
    local DeusExLevelInfo info;

    foreach AllActors(class'DeusExLevelInfo', info)
        break;

    return info;
}

//
// If player chose to dual map the F keys
//
exec function DualmapF3() { if ( AugmentationSystem != None) AugmentationSystem.ActivateAugByKey(0); }
exec function DualmapF4() { if ( AugmentationSystem != None) AugmentationSystem.ActivateAugByKey(1); }
exec function DualmapF5() { if ( AugmentationSystem != None) AugmentationSystem.ActivateAugByKey(2); }
exec function DualmapF6() { if ( AugmentationSystem != None) AugmentationSystem.ActivateAugByKey(3); }
exec function DualmapF7() { if ( AugmentationSystem != None) AugmentationSystem.ActivateAugByKey(4); }
exec function DualmapF8() { if ( AugmentationSystem != None) AugmentationSystem.ActivateAugByKey(5); }
exec function DualmapF9() { if ( AugmentationSystem != None) AugmentationSystem.ActivateAugByKey(6); }
exec function DualmapF10() { if ( AugmentationSystem != None) AugmentationSystem.ActivateAugByKey(7); }
exec function DualmapF11() { if ( AugmentationSystem != None) AugmentationSystem.ActivateAugByKey(8); }
exec function DualmapF12() { if ( AugmentationSystem != None) AugmentationSystem.ActivateAugByKey(9); }

//
// Team Say
//
exec function TeamSay( string Msg )
{
    local Pawn P;
    local String str;

    if ( TeamDMGame(DXGame) == None )
    {
        Say(Msg);
        return;
    }

    str = PlayerReplicationInfo.PlayerName $ ": " $ Msg;

    if ( Role == ROLE_Authority )
        log( "TeamSay>" $ str );

    for( P=Level.PawnList; P!=None; P=P.nextPawn )
    {
        if( P.bIsPlayer && (P.PlayerReplicationInfo.Team == PlayerReplicationInfo.Team) )
        {
            if ( P.IsA('DeusExPlayer') )
                DeusExPlayer(P).ClientMessage( str, 'TeamSay', true );
        }
    }
}

// ----------------------------------------------------------------------
// RestartLevel()
// ----------------------------------------------------------------------

exec function RestartLevel()
{
    ResetPlayer();
    Super.RestartLevel();
}

// ----------------------------------------------------------------------
// LoadGame()
// ----------------------------------------------------------------------

exec function LoadGame(int saveIndex)
{
    // Reset the FOV
    DesiredFOV = Default.DesiredFOV;

    DeusExRootWindow(rootWindow).ClearWindowStack();
    ClientTravel("?loadgame=" $ saveIndex, TRAVEL_Absolute, False);
}

// ----------------------------------------------------------------------
// QuickSave()
// ----------------------------------------------------------------------

exec function QuickSave()
{
    local DeusExLevelInfo info;

    info = GetLevelInfo();

    // Don't allow saving if:
    //
    // 1) The player is dead
    // 2) We're on the logo map
    // 4) We're interpolating (playing outtro)
    // 3) A datalink is playing
   // 4) We're in a multiplayer game

    if (((info != None) && (info.MissionNumber < 0)) || 
       ((IsInState('Dying')) || (IsInState('Paralyzed')) || (IsInState('Interpolating'))) || 
       (dataLinkPlay != None) || (Level.Netmode != NM_Standalone))
    {
       return;
    }

    SaveGame(-1, QuickSaveGameTitle);
}

// ----------------------------------------------------------------------
// QuickLoad()
// ----------------------------------------------------------------------

exec function QuickLoad()
{
   //Don't allow in multiplayer.

   if (Level.Netmode != NM_Standalone)
      return;

    if (DeusExRootWindow(rootWindow) != None) 
        DeusExRootWindow(rootWindow).ConfirmQuickLoad();
}

// ----------------------------------------------------------------------
// QuickLoadConfirmed()
// ----------------------------------------------------------------------

function QuickLoadConfirmed()
{
   if (Level.Netmode != NM_Standalone)
      return;
    LoadGame(-1);
}

// ----------------------------------------------------------------------
// BuySkillSound()
// ----------------------------------------------------------------------

function BuySkillSound( int code )
{
    local Sound snd;

    switch( code )
    {
        case 0:
            snd = Sound'Menu_OK';
            break;
        case 1:
            snd = Sound'Menu_Cancel';
            break;
        case 2:
            snd = Sound'Menu_Focus';
            break;
        case 3:
            snd = Sound'Menu_BuySkills';
            break;
    }
    PlaySound( snd, SLOT_Interface, 0.75 );
}

// ----------------------------------------------------------------------
// StartNewGame()
//
// Starts a new game given the map passed in
// ----------------------------------------------------------------------

exec function StartNewGame(String startMap)
{
    if (DeusExRootWindow(rootWindow) != None)
        DeusExRootWindow(rootWindow).ClearWindowStack();

    // Set a flag designating that we're traveling,
    // so MissionScript can check and not call FirstFrame() for this map.
    flagBase.SetBool('PlayerTraveling', True, True, 0);

    SaveSkillPoints();
    ResetPlayer();
    DeleteSaveGameFiles();

    bStartingNewGame = True;

    // Send the player to the specified map!
    if (startMap == "")
        Level.Game.SendPlayer(Self, "01_NYC_UNATCOIsland");     // TODO: Must be stored somewhere!
    else
        Level.Game.SendPlayer(Self, startMap);
}

// ----------------------------------------------------------------------
// StartTrainingMission()
// ----------------------------------------------------------------------

function StartTrainingMission()
{
    if (DeusExRootWindow(rootWindow) != None)
        DeusExRootWindow(rootWindow).ClearWindowStack();

   // Make sure the player isn't asked to do this more than
    // once if prompted on the main menu.
    if (!bAskedToTrain)
    {
        bAskedToTrain = True;
        SaveConfig();
    }

   SkillSystem.ResetSkills();
    ResetPlayer(True);
    DeleteSaveGameFiles();
    bStartingNewGame = True;
    Level.Game.SendPlayer(Self, "00_Training");
}

// ----------------------------------------------------------------------
// ShowIntro()
// ----------------------------------------------------------------------

function ShowIntro(optional bool bStartNewGame)
{
    if (DeusExRootWindow(rootWindow) != None)
        DeusExRootWindow(rootWindow).ClearWindowStack();

    bStartNewGameAfterIntro = bStartNewGame;

    // Make sure all augmentations are OFF before going into the intro
    AugmentationSystem.DeactivateAll();

    // Reset the player
    Level.Game.SendPlayer(Self, "00_Intro");
}

// ----------------------------------------------------------------------
// ShowCredits()
// ----------------------------------------------------------------------

function ShowCredits(optional bool bLoadIntro)
{
    local DeusExRootWindow root;
    local CreditsWindow winCredits;

    root = DeusExRootWindow(rootWindow);

    if (root != None)
    {
        // Show the credits screen and force the game not to pause
        // if we're showing the credits after the endgame
        winCredits = CreditsWindow(root.InvokeMenuScreen(Class'CreditsWindow', bLoadIntro));
        winCredits.SetLoadIntro(bLoadIntro);
    }
}

// ----------------------------------------------------------------------
// StartListenGame()
// ----------------------------------------------------------------------

function StartListenGame(string options)
{
   local DeusExRootWindow root;

   root = DeusExRootWindow(rootWindow);

   if (root != None)
      root.ClearWindowStack();

   ConsoleCommand("start "$options$"?listen");
}

// ----------------------------------------------------------------------
// StartMultiplayerGame()
// ----------------------------------------------------------------------

function StartMultiplayerGame(string command)
{
   local DeusExRootWindow root;

   root = DeusExRootWindow(rootWindow);

   if (root != None)
      root.ClearWindowStack();

   ConsoleCommand(command);
}

// ----------------------------------------------------------------------
// NewMultiplayerMatch()
// ----------------------------------------------------------------------

function NewMultiplayerMatch()
{
    DeusExMPGame( DXGame ).RestartPlayer( Self );
    PlayerReplicationInfo.Score = 0;
    PlayerReplicationInfo.Deaths = 0;
    PlayerReplicationInfo.Streak = 0;
}

// ----------------------------------------------------------------------
// ShowMultiplayerWin()
// ----------------------------------------------------------------------

function ShowMultiplayerWin( String winnerName, int winningTeam, String Killer, String Killee, String Method )
{
    local HUDMultiplayer mpScr;
    local DeusExRootWindow root;

    if (( Player != None ) && ( Player.Console != None ))
        Player.Console.ClearMessages();

    root = DeusExRootWindow(rootWindow);

    if ( root != None )
    {
        mpScr = HUDMultiplayer(root.InvokeUIScreen(Class'HUDMultiplayer', True));
        root.MaskBackground(True);

        if ( mpScr != None )
        {
         mpScr.winnerName = winnerName;
            mpScr.winningTeam = winningTeam;
            mpScr.winKiller = Killer;
            mpScr.winKillee = Killee;
            mpScr.winMethod = Method;
        }
    }

   //Do cleanup
   if (PlayerIsClient())
   {
      if (AugmentationSystem != None)
         AugmentationSystem.DeactivateAll();
   }
}


// ----------------------------------------------------------------------
// ResetPlayer()
//
// Called when a new game is started. 
//
// 1) Erase all flags except those beginning with "SKTemp_"
// 2) Dumps inventory
// 3) Restore any other defaults
// ----------------------------------------------------------------------

function ResetPlayer(optional bool bTraining)
{
    local inventory anItem;
    local inventory nextItem;

    ResetPlayerToDefaults();

    // Reset Augmentations
    if (AugmentationSystem != None)
    {
        AugmentationSystem.ResetAugmentations();
        AugmentationSystem.Destroy();
        AugmentationSystem = None;
    }

    // Give the player a pistol and a prod
    if (!bTraining)
    {
        anItem = Spawn(class'WeaponPistol');
        anItem.Frob(Self, None);
        anItem.bInObjectBelt = True;
        anItem = Spawn(class'WeaponProd');
        anItem.Frob(Self, None);
        anItem.bInObjectBelt = True;
        anItem = Spawn(class'MedKit');
        anItem.Frob(Self, None);
        anItem.bInObjectBelt = True;
    }
}

// ----------------------------------------------------------------------
// ResetPlayerToDefaults()
//
// Resets all travel variables to their defaults
// ----------------------------------------------------------------------

function ResetPlayerToDefaults()
{
    local inventory anItem;
    local inventory nextItem;

   // reset the image linked list
    FirstImage = None;

    if (DeusExRootWindow(rootWindow) != None)
        DeusExRootWindow(rootWindow).ResetFlags();

    // Remove all the keys from the keyring before
    // it gets destroyed
    if (KeyRing != None)
    {
        KeyRing.RemoveAllKeys();
      if ((Role == ROLE_Authority) && (Level.NetMode != NM_Standalone))
      {
         KeyRing.ClientRemoveAllKeys();
      }
        KeyRing = None;
    }

    while(Inventory != None)
    {
        anItem = Inventory;
        DeleteInventory(anItem);
        anItem.Destroy();
    }

    // Clear object belt
    if (DeusExRootWindow(rootWindow) != None)
        DeusExRootWindow(rootWindow).hud.belt.ClearBelt();

    // clear the notes and the goals
    DeleteAllNotes();
    DeleteAllGoals();

    // Nuke the history
    ResetConversationHistory();

    // Other defaults
    Credits = Default.Credits;
    Energy  = Default.Energy;
    SkillPointsTotal = Default.SkillPointsTotal;
    SkillPointsAvail = Default.SkillPointsAvail;

    SetInHandPending(None);
    SetInHand(None);

    bInHandTransition = False;

    RestoreAllHealth();
    ClearLog();

    // Reset save count/time
    saveCount = 0;
    saveTime  = 0.0;

    // Reinitialize all subsystems we've just nuked
    InitializeSubSystems();

   // Give starting inventory.
   if (Level.Netmode != NM_Standalone)
    {
        NintendoImmunityEffect( True );
      GiveInitialInventory();
    }
}

// ----------------------------------------------------------------------
// CreateKeyRing()
// ----------------------------------------------------------------------

function CreateKeyRing()
{
    if (KeyRing == None)
    {
        KeyRing = Spawn(class'NanoKeyRing', Self);
        KeyRing.InitialState='Idle2';
        KeyRing.GiveTo(Self);
        KeyRing.SetBase(Self);
    }
}

// ----------------------------------------------------------------------
// DrugEffects()
// ----------------------------------------------------------------------

simulated function DrugEffects(float deltaTime)
{
    local float mult, fov;
    local Rotator rot;
    local DeusExRootWindow root;

    root = DeusExRootWindow(rootWindow);

    // random wandering and swaying when drugged
    if (drugEffectTimer > 0)
    {
        if ((root != None) && (root.hud != None))
        {
            if (root.hud.background == None)
            {
                root.hud.SetBackground(Texture'DrunkFX');
                root.hud.SetBackgroundSmoothing(True);
                root.hud.SetBackgroundStretching(True);
                root.hud.SetBackgroundStyle(DSTY_Modulated);
            }
        }

        mult = FClamp(drugEffectTimer / 10.0, 0.0, 3.0);
        rot.Pitch = 1024.0 * Cos(Level.TimeSeconds * mult) * deltaTime * mult;
        rot.Yaw = 1024.0 * Sin(Level.TimeSeconds * mult) * deltaTime * mult;
        rot.Roll = 0;

        rot.Pitch = FClamp(rot.Pitch, -4096, 4096);
        rot.Yaw = FClamp(rot.Yaw, -4096, 4096);

        ViewRotation += rot;

        if ( Level.NetMode == NM_Standalone )
        {
            fov = Default.DesiredFOV - drugEffectTimer + Rand(2);
            fov = FClamp(fov, 30, Default.DesiredFOV);
            DesiredFOV = fov;
        }
        else
            DesiredFOV = Default.DesiredFOV;

        drugEffectTimer -= deltaTime;
        if (drugEffectTimer < 0)
            drugEffectTimer = 0;
    }
    else
    {
        if ((root != None) && (root.hud != None))
        {
            if (root.hud.background != None)
            {
                root.hud.SetBackground(None);
                root.hud.SetBackgroundStyle(DSTY_Normal);
                DesiredFOV = Default.DesiredFOV;
            }
        }
    }
}

// ----------------------------------------------------------------------
// PlayMusic()
// ----------------------------------------------------------------------

function PlayMusic(String musicToPlay, optional int sectionToPlay)
{
    local Music LoadedMusic;
    local EMusicMode newMusicMode;

    if (musicToPlay != "")
    {
        LoadedMusic = Music(DynamicLoadObject(musicToPlay $ "." $ musicToPlay, class'Music'));

        if (LoadedMusic != None)
        {
            switch(sectionToPlay)
            {
                case 0:  newMusicMode = MUS_Ambient; break;
                case 1:  newMusicMode = MUS_Combat; break;
                case 2:  newMusicMode = MUS_Conversation; break;
                case 3:  newMusicMode = MUS_Outro; break;
                case 4:  newMusicMode = MUS_Dying; break;
                default: newMusicMode = MUS_Ambient; break;
            }

            ClientSetMusic(LoadedMusic, newMusicMode, 255, MTRAN_FastFade);
        }
    }
}

// ----------------------------------------------------------------------
// PlayMusicWindow()
//
// Displays the Load Map dialog
// ----------------------------------------------------------------------

exec function PlayMusicWindow()
{
    if (!bCheatsEnabled)
        return;

    InvokeUIScreen(Class'PlayMusicWindow');
}

// ----------------------------------------------------------------------
// UpdateDynamicMusic()
//
// Pattern definitions:
//   0 - Ambient 1
//   1 - Dying
//   2 - Ambient 2 (optional)
//   3 - Combat
//   4 - Conversation
//   5 - Outro
// ----------------------------------------------------------------------

function UpdateDynamicMusic(float deltaTime)
{
    local bool bCombat;
    local ScriptedPawn npc;
   local Pawn CurPawn;
    local DeusExLevelInfo info;

    if (Level.Song == None)
        return;

   // DEUS_EX AMSD In singleplayer, do the old thing.
   // In multiplayer, we can come out of dying.
   if (!PlayerIsClient())
   {
      if ((musicMode == MUS_Dying) || (musicMode == MUS_Outro))
         return;
   }
   else
   {
      if (musicMode == MUS_Outro)
         return;
   }
      

    musicCheckTimer += deltaTime;
    musicChangeTimer += deltaTime;

    if (IsInState('Interpolating'))
    {
        // don't mess with the music on any of the intro maps
        info = GetLevelInfo();
        if ((info != None) && (info.MissionNumber < 0))
        {
            musicMode = MUS_Outro;
            return;
        }

        if (musicMode != MUS_Outro)
        {
            ClientSetMusic(Level.Song, 5, 255, MTRAN_FastFade);
            musicMode = MUS_Outro;
        }
    }
    else if (IsInState('Conversation'))
    {
        if (musicMode != MUS_Conversation)
        {
            // save our place in the ambient track
            if (musicMode == MUS_Ambient)
                savedSection = SongSection;
            else
                savedSection = 255;

            ClientSetMusic(Level.Song, 4, 255, MTRAN_Fade);
            musicMode = MUS_Conversation;
        }
    }
    else if (IsInState('Dying'))
    {
        if (musicMode != MUS_Dying)
        {
            ClientSetMusic(Level.Song, 1, 255, MTRAN_Fade);
            musicMode = MUS_Dying;
        }
    }
    else
    {
        // only check for combat music every second
        if (musicCheckTimer >= 1.0)
        {
            musicCheckTimer = 0.0;
            bCombat = False;

            // check a 100 foot radius around me for combat
         // XXXDEUS_EX AMSD Slow Pawn Iterator
         //foreach RadiusActors(class'ScriptedPawn', npc, 1600)
         for (CurPawn = Level.PawnList; CurPawn != None; CurPawn = CurPawn.NextPawn)
         {
            npc = ScriptedPawn(CurPawn);
            if ((npc != None) && (VSize(npc.Location - Location) < (1600 + npc.CollisionRadius)))
            {
               if ((npc.GetStateName() == 'Attacking') && (npc.Enemy == Self))
               {
                  bCombat = True;
                  break;
               }
            }
         }

            if (bCombat)
            {
                musicChangeTimer = 0.0;

                if (musicMode != MUS_Combat)
                {
                    // save our place in the ambient track
                    if (musicMode == MUS_Ambient)
                        savedSection = SongSection;
                    else
                        savedSection = 255;

                    ClientSetMusic(Level.Song, 3, 255, MTRAN_FastFade);
                    musicMode = MUS_Combat;
                }
            }
            else if (musicMode != MUS_Ambient)
            {
                // wait until we've been out of combat for 5 seconds before switching music
                if (musicChangeTimer >= 5.0)
                {
                    // use the default ambient section for this map
                    if (savedSection == 255)
                        savedSection = Level.SongSection;

                    // fade slower for combat transitions
                    if (musicMode == MUS_Combat)
                        ClientSetMusic(Level.Song, savedSection, 255, MTRAN_SlowFade);
                    else
                        ClientSetMusic(Level.Song, savedSection, 255, MTRAN_Fade);

                    savedSection = 255;
                    musicMode = MUS_Ambient;
                    musicChangeTimer = 0.0;
                }
            }
        }
    }
}

// ----------------------------------------------------------------------
// MaintainEnergy()
// ----------------------------------------------------------------------

function MaintainEnergy(float deltaTime)
{
    local Float energyUse;
   local Float energyRegen;

    // make sure we can't continue to go negative if we take damage
    // after we're already out of energy
    if (Energy <= 0)
    {
        Energy = 0;
        EnergyDrain = 0;
        EnergyDrainTotal = 0;
    }

   energyUse = 0;

    // Don't waste time doing this if the player is dead or paralyzed
    if ((!IsInState('Dying')) && (!IsInState('Paralyzed')))
   {
      if (Energy > 0)
      {
         // Decrement energy used for augmentations
         energyUse = AugmentationSystem.CalcEnergyUse(deltaTime);
         
         Energy -= EnergyUse;
         
         // Calculate the energy drain due to EMP attacks
         if (EnergyDrain > 0)
         {
            energyUse = EnergyDrainTotal * deltaTime;
            Energy -= EnergyUse;
            EnergyDrain -= EnergyUse;
            if (EnergyDrain <= 0)
            {
               EnergyDrain = 0;
               EnergyDrainTotal = 0;
            }
         }
      }

      //Do check if energy is 0.  
      // If the player's energy drops to zero, deactivate 
      // all augmentations
      if (Energy <= 0)
      {
         //If we were using energy, then tell the client we're out.
         //Otherwise just make sure things are off.  If energy was
         //already 0, then energy use will still be 0, so we won't
         //spam.  DEUS_EX AMSD
         if (energyUse > 0)         
            ClientMessage(EnergyDepleted);
         Energy = 0;
         EnergyDrain = 0;
         EnergyDrainTotal = 0;         
         AugmentationSystem.DeactivateAll();
      }

      // If all augs are off, then start regenerating in multiplayer,
      // up to 25%.
      if ((energyUse == 0) && (Energy <= MaxRegenPoint) && (Level.NetMode != NM_Standalone))
      {
         energyRegen = RegenRate * deltaTime;
         Energy += energyRegen;
      }
    }
}
// ----------------------------------------------------------------------
// RefreshSystems()
// DEUS_EX AMSD For keeping multiplayer working in better shape
// ----------------------------------------------------------------------

simulated function RefreshSystems(float DeltaTime)
{
    local DeusExRootWindow root;

   if (Level.NetMode == NM_Standalone)
      return;

   if (Role == ROLE_Authority)
      return;

   if (LastRefreshTime < 0)
      LastRefreshTime = 0;

   LastRefreshTime = LastRefreshTime + DeltaTime;

   if (LastRefreshTime < 0.25)
      return;
    
   if (AugmentationSystem != None)   
      AugmentationSystem.RefreshAugDisplay();
   
   root = DeusExRootWindow(rootWindow);
   if (root != None)    
      root.RefreshDisplay(LastRefreshTime);

   RepairInventory();

   LastRefreshTime = 0;

}

function RepairInventory()
{
   local byte               LocalInvSlots[30];      // 5x6 grid of inventory slots
   local int i;
    local int slotsCol;
    local int slotsRow;
   local Inventory curInv;

   if ((Level.NetMode != NM_Standalone) && (bBeltIsMPInventory))
      return;

   //clean out our temp inventory.
   for (i = 0; i < 30; i++)
      LocalInvSlots[i] = 0;

   // go through our inventory and fill localinvslots
   if (Inventory != None)
   {
      for (curInv = Inventory; curInv != None; curInv = curInv.Inventory)
      {
         // Make sure this item is located in a valid position
         if (( curInv.invPosX != -1 ) && ( curInv.invPosY != -1 ))
         {
            // fill inventory slots
            for( slotsRow=0; slotsRow < curInv.invSlotsY; slotsRow++ )
               for ( slotsCol=0; slotsCol < curInv.invSlotsX; slotsCol++ )
                  LocalInvSlots[((slotsRow + curInv.invPosY) * maxInvCols) + (slotscol + curInv.invPosX)] = 1;
         }
      }
   }

   // verify that the 2 inventory grids match
   for (i = 0; i < 30; i++)
      if (LocalInvSlots[i] < invSlots[i]) //don't stuff slots, that can get handled elsewhere, just clear ones that need it
      {
         log("ERROR!!! Slot "$i$" should be "$LocalInvSlots[i]$", but isn't!!!!, repairing");
         invSlots[i] = LocalInvSlots[i];
      }

}

// ----------------------------------------------------------------------
// Bleed()
// 
// Let the blood flow
// ----------------------------------------------------------------------

function Bleed(float deltaTime)
{
    local float  dropPeriod;
    local float  adjustedRate;
    local vector bloodVector;

   if ((DeusExMPGame(Level.Game) != None) && (!DeusExMPGame(Level.Game).bSpawnEffects))
   {
      bleedrate = 0;
      dropCounter = 0;
      return;
   }

    // Copied from ScriptedPawn::Tick()
    bleedRate = FClamp(bleedRate, 0.0, 1.0);
    if (bleedRate > 0)
    {
        adjustedRate = (1.0-bleedRate)*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)
        {
            bloodVector = vect(0,0,1)*CollisionHeight*0.5;  // so folks don't bleed from the crotch
            spawn(Class'BloodDrop',,,bloodVector+Location);
            dropCounter -= dropPeriod;
        }
        bleedRate -= deltaTime/clotPeriod;
    }
    if (bleedRate <= 0)
    {
        dropCounter = 0;
        bleedRate   = 0;
    }
}

// ----------------------------------------------------------------------
// UpdatePoison()
// 
// Get all woozy 'n' stuff
// ----------------------------------------------------------------------

function UpdatePoison(float deltaTime)
{
    if (Health <= 0)  // no more pain -- you're already dead!
        return;

    if (InConversation())  // kinda hacky...
        return;

    if (poisonCounter > 0)
    {
        poisonTimer += deltaTime;
        if (poisonTimer >= 2.0)  // pain every two seconds
        {
            poisonTimer = 0;
            poisonCounter--;
            TakeDamage(poisonDamage, myPoisoner, Location, vect(0,0,0), 'PoisonEffect');
        }
        if ((poisonCounter <= 0) || (Health <= 0))
            StopPoison();
    }
}

// ----------------------------------------------------------------------
// StartPoison()
// 
// Gakk!  We've been poisoned!
// ----------------------------------------------------------------------

function StartPoison( Pawn poisoner, int Damage )
{
    local float augLevel;

    if ( Level.NetMode != NM_Standalone )
    {
        // Don't do poison and drug effects if in multiplayer and AugEnviro is on
        augLevel = AugmentationSystem.GetAugLevelValue(class'AugEnviro');
        if ( augLevel != -1.0 )
            return;
    }

    myPoisoner = poisoner;

    if (Health <= 0)  // no more pain -- you're already dead!
        return;

    if (InConversation())  // kinda hacky...
        return;

    poisonCounter = 4;    // take damage no more than four times (over 8 seconds)
    poisonTimer   = 0;    // reset pain timer
    if (poisonDamage < Damage)  // set damage amount
        poisonDamage = Damage;

    drugEffectTimer += 4;  // make the player vomit for the next four seconds

    // In multiplayer, don't let the effect last longer than 30 seconds
    if ( Level.NetMode != NM_Standalone )
    {
        if ( drugEffectTimer > 30 )
            drugEffectTimer = 30;
    }
}

// ----------------------------------------------------------------------
// StopPoison()
// 
// Stop the pain
// ----------------------------------------------------------------------

function StopPoison()
{
    myPoisoner = None;
    poisonCounter = 0;
    poisonTimer   = 0;
    poisonDamage  = 0;
}

// ----------------------------------------------------------------------
// SpawnEMPSparks()
// 
// Spawn sparks for items affected by Warren's EMP Field
// ----------------------------------------------------------------------

function SpawnEMPSparks(Actor empActor, Rotator rot)
{
    local ParticleGenerator sparkGen;

    if ((empActor == None) || empActor.bDeleteMe)
        return;

    sparkGen = Spawn(class'ParticleGenerator', empActor,, empActor.Location, rot);
    if (sparkGen != None)
    {
        sparkGen.SetBase(empActor);
        sparkGen.LifeSpan = 3;
        sparkGen.particleTexture = Texture'Effects.Fire.SparkFX1';
        sparkGen.particleDrawScale = 0.1;
        sparkGen.bRandomEject = True;
        sparkGen.ejectSpeed = 100.0;
        sparkGen.bGravity = True;
        sparkGen.bParticlesUnlit = True;
        sparkGen.frequency = 1.0;
        sparkGen.riseRate = 10;
        sparkGen.spawnSound = Sound'Spark2';
    }
}

// ----------------------------------------------------------------------
// UpdateWarrenEMPField()
// 
// Update Warren's EMP field
// ----------------------------------------------------------------------

function UpdateWarrenEMPField(float deltaTime)
{
    local float          empRadius;
    local Robot          curRobot;
    local AlarmUnit      curAlarm;
    local AutoTurret     curTurret;
    local LaserTrigger   curLaser;
    local BeamTrigger    curBeam;
    local SecurityCamera curCamera;
    local int            option;

    if (bWarrenEMPField)
    {
        WarrenTimer -= deltaTime;
        if (WarrenTimer <= 0)
        {
            WarrenTimer = 0.15;

            empRadius = 600;
            if (WarrenSlot == 0)
            {
                foreach RadiusActors(Class'Robot', curRobot, empRadius)
                {
                    if ((curRobot.LastRendered() < 2.0) && (curRobot.CrazedTimer <= 0) &&
                        (curRobot.EMPHitPoints > 0))
                    {
                        if (curRobot.GetPawnAllianceType(self) == ALLIANCE_Hostile)
                            option = Rand(2);
                        else
                            option = 0;
                        if (option == 0)
                            curRobot.TakeDamage(curRobot.EMPHitPoints*2, self, curRobot.Location, vect(0,0,0), 'EMP');
                        else
                            curRobot.TakeDamage(100, self, curRobot.Location, vect(0,0,0), 'NanoVirus');
                        SpawnEMPSparks(curRobot, Rotator(Location-curRobot.Location));
                    }
                }
            }
            else if (WarrenSlot == 1)
            {
                foreach RadiusActors(Class'AlarmUnit', curAlarm, empRadius)
                {
                    if ((curAlarm.LastRendered() < 2.0) && !curAlarm.bConfused)
                    {
                        curAlarm.TakeDamage(100, self, curAlarm.Location, vect(0,0,0), 'EMP');
                        SpawnEMPSparks(curAlarm, curAlarm.Rotation);
                    }
                }
            }
            else if (WarrenSlot == 2)
            {
                foreach RadiusActors(Class'AutoTurret', curTurret, empRadius)
                {
                    if ((curTurret.LastRendered() < 2.0) && !curTurret.bConfused)
                    {
                        curTurret.TakeDamage(100, self, curTurret.Location, vect(0,0,0), 'EMP');
                        SpawnEMPSparks(curTurret, Rotator(Location-curTurret.Location));
                    }
                }
            }
            else if (WarrenSlot == 3)
            {
                foreach RadiusActors(Class'LaserTrigger', curLaser, empRadius)
                {
                    if ((curLaser.LastRendered() < 2.0) && !curLaser.bConfused)
                    {
                        curLaser.TakeDamage(100, self, curLaser.Location, vect(0,0,0), 'EMP');
                        SpawnEMPSparks(curLaser, curLaser.Rotation);
                    }
                }
            }
            else if (WarrenSlot == 4)
            {
                foreach RadiusActors(Class'BeamTrigger', curBeam, empRadius)
                {
                    if ((curBeam.LastRendered() < 2.0) && !curBeam.bConfused)
                    {
                        curBeam.TakeDamage(100, self, curBeam.Location, vect(0,0,0), 'EMP');
                        SpawnEMPSparks(curBeam, curBeam.Rotation);
                    }
                }
            }
            else if (WarrenSlot == 5)
            {
                foreach RadiusActors(Class'SecurityCamera', curCamera, empRadius)
                {
                    if ((curCamera.LastRendered() < 2.0) && !curCamera.bConfused)
                    {
                        curCamera.TakeDamage(100, self, curCamera.Location, vect(0,0,0), 'EMP');
                        SpawnEMPSparks(curCamera, Rotator(Location-curCamera.Location));
                    }
                }
            }

            WarrenSlot++;
            if (WarrenSlot >= 6)
                WarrenSlot = 0;
        }
    }
}


// ----------------------------------------------------------------------
// UpdateTranslucency()
// DEUS_EX AMSD Try to make the player harder to see if he is in darkness.
// ----------------------------------------------------------------------

function UpdateTranslucency(float DeltaTime)
{
   local float DarkVis;
   local float CamoVis;
    local AdaptiveArmor armor;
   local bool bMakeTranslucent;
   local DeusExMPGame Game;
   
   // Don't do it in multiplayer.
   if (Level.NetMode == NM_Standalone)
      return;

   Game = DeusExMPGame(Level.Game);
   if (Game == None)
   {
      return;
   }

   bMakeTranslucent = false;

   //DarkVis = AIVisibility(TRUE);
   DarkVis = 1.0;

   CamoVis = 1.0;

   //Check cloaking.
    if (AugmentationSystem.GetAugLevelValue(class'AugCloak') != -1.0)
   {
      bMakeTranslucent = TRUE;
      CamoVis = Game.CloakEffect;
   }

   // If you have a weapon out, scale up the camo and turn off the cloak.
   // Adaptive armor leaves you completely invisible, but drains quickly.
   if ((inHand != None) && (inHand.IsA('DeusExWeapon')) && (CamoVis < 1.0))
   {
      CamoVis = 1.0;
      bMakeTranslucent=FALSE;
      ClientMessage(WeaponUnCloak);
      AugmentationSystem.FindAugmentation(class'AugCloak').Deactivate();
   }
   
   // go through the actor list looking for owned AdaptiveArmor
   // since they aren't in the inventory anymore after they are used
   if (UsingChargedPickup(class'AdaptiveArmor'))
      {
         CamoVis = CamoVis * Game.CloakEffect;
         bMakeTranslucent = TRUE;
      }

   ScaleGlow = Default.ScaleGlow * CamoVis * DarkVis;

   //Translucent is < 0.1, untranslucent if > 0.2, not same edge to prevent sharp breaks.
   if (bMakeTranslucent)
   {
      Style = STY_Translucent;
      if (Self.IsA('JCDentonMale'))
      {
         MultiSkins[6] = Texture'BlackMaskTex';
         MultiSkins[7] = Texture'BlackMaskTex';
      }
   }
   else if (Game.bDarkHiding)
   {
      if (CamoVis * DarkVis < Game.StartHiding)
         Style = STY_Translucent;
      if (CamoVis * DarkVis > Game.EndHiding)
         Style = Default.Style;
   }
   else if (!bMakeTranslucent)
   {
      if (Self.IsA('JCDentonMale'))
      {
         MultiSkins[6] = Default.MultiSkins[6];
         MultiSkins[7] = Default.MultiSkins[7];
      }
      Style = Default.Style;
   }
}

// ----------------------------------------------------------------------
// RestoreSkillPoints()
// 
// Restore skill point variables
// ----------------------------------------------------------------------

function RestoreSkillPoints()
{
    local name flagName;

    bSavingSkillsAugs = False;

    // Get the skill points available
    flagName = rootWindow.StringToName("SKTemp_SkillPointsAvail");
    if (flagBase.CheckFlag(flagName, FLAG_Int))
    {
        SkillPointsAvail = flagBase.GetInt(flagName);
        flagBase.DeleteFlag(flagName, FLAG_Int);
    }

    // Get the skill points total
    flagName = rootWindow.StringToName("SKTemp_SkillPointsTotal");
    if (flagBase.CheckFlag(flagName, FLAG_Int))
    {
        SkillPointsTotal = flagBase.GetInt(flagName);
        flagBase.DeleteFlag(flagName, FLAG_Int);
    }
}

// ----------------------------------------------------------------------
// SaveSkillPoints()
// 
// Saves out skill points, used when starting a new game
// ----------------------------------------------------------------------

function SaveSkillPoints()
{
    local name flagName;

    // Save/Restore must be done as atomic unit
    if (bSavingSkillsAugs)
        return;

    bSavingSkillsAugs = True;

    // Save the skill points available
    flagName = rootWindow.StringToName("SKTemp_SkillPointsAvail");
    flagBase.SetInt(flagName, SkillPointsAvail);

    // Save the skill points available
    flagName = rootWindow.StringToName("SKTemp_SkillPointsTotal");
    flagBase.SetInt(flagName, SkillPointsTotal);
}

// ----------------------------------------------------------------------
// AugAdd()
//
// Augmentation system functions
// exec functions for command line for demo
// ----------------------------------------------------------------------

exec function AugAdd(class<Augmentation> aWantedAug)
{
    local Augmentation anAug;

    if (!bCheatsEnabled)
        return;

    if (AugmentationSystem != None)
    {
        anAug = AugmentationSystem.GivePlayerAugmentation(aWantedAug);

        if (anAug == None)
            ClientMessage(GetItemName(String(aWantedAug)) $ " is not a valid augmentation!");
    }
}

// ----------------------------------------------------------------------
// ActivateAugmentation()
// ----------------------------------------------------------------------

exec function ActivateAugmentation(int num)
{
    local Augmentation anAug;
    local int count, wantedSlot, slotIndex;
    local bool bFound;

    if (RestrictInput())
        return;

    if (Energy == 0)
    {
        ClientMessage(EnergyDepleted);
        PlaySound(AugmentationSystem.FirstAug.DeactivateSound, SLOT_None);
        return;
    }

    if (AugmentationSystem != None)
        AugmentationSystem.ActivateAugByKey(num);
}

// ----------------------------------------------------------------------
// ActivateAllAugs()
// ----------------------------------------------------------------------

exec function ActivateAllAugs()
{
    if (AugmentationSystem != None)
        AugmentationSystem.ActivateAll();
}

// ----------------------------------------------------------------------
// DeactivateAllAugs()
// ----------------------------------------------------------------------

exec function DeactivateAllAugs()
{
    if (AugmentationSystem != None)
        AugmentationSystem.DeactivateAll();
}

// ----------------------------------------------------------------------
// SwitchAmmo()
// ----------------------------------------------------------------------

exec function SwitchAmmo()
{
    if (inHand.IsA('DeusExWeapon'))
        DeusExWeapon(inHand).CycleAmmo();   
}

// ----------------------------------------------------------------------
// RemoveInventoryType()
// ----------------------------------------------------------------------

function RemoveInventoryType(Class<Inventory> removeType)
{
    local Inventory item;

    item = FindInventoryType(removeType);

    if (item != None)
        DeleteInventory(item);
}

// ----------------------------------------------------------------------
// AddAugmentationDisplay()
// ----------------------------------------------------------------------

function AddAugmentationDisplay(Augmentation aug)
{
   //DEUS_EX AMSD Added none check here.
    if ((rootWindow != None) && (aug != None))
        DeusExRootWindow(rootWindow).hud.activeItems.AddIcon(aug.SmallIcon, aug);
}

// ----------------------------------------------------------------------
// RemoveAugmentationDisplay()
// ----------------------------------------------------------------------

function RemoveAugmentationDisplay(Augmentation aug)
{
    DeusExRootWindow(rootWindow).hud.activeItems.RemoveIcon(aug);
}

// ----------------------------------------------------------------------
// ClearAugmentationDisplay()
// ----------------------------------------------------------------------

function ClearAugmentationDisplay()
{
    DeusExRootWindow(rootWindow).hud.activeItems.ClearAugmentationDisplay();
}

// ----------------------------------------------------------------------
// UpdateAugmentationDisplayStatus()
// ----------------------------------------------------------------------

function UpdateAugmentationDisplayStatus(Augmentation aug)
{
    DeusExRootWindow(rootWindow).hud.activeItems.UpdateAugIconStatus(aug);
}

// ----------------------------------------------------------------------
// AddChargedDisplay()
// ----------------------------------------------------------------------

function AddChargedDisplay(ChargedPickup item)
{
   if ( (PlayerIsClient()) || (Level.NetMode == NM_Standalone) )    
      DeusExRootWindow(rootWindow).hud.activeItems.AddIcon(item.ChargedIcon, item);
}

// ----------------------------------------------------------------------
// RemoveChargedDisplay()
// ----------------------------------------------------------------------

function RemoveChargedDisplay(ChargedPickup item)
{
   if ( (PlayerIsClient()) || (Level.NetMode == NM_Standalone) )    
      DeusExRootWindow(rootWindow).hud.activeItems.RemoveIcon(item);
}

// ----------------------------------------------------------------------
// ActivateKeypadWindow()
// DEUS_EX AMSD Has to be here because player doesn't own keypad, so
// func rep doesn't work right.
// ----------------------------------------------------------------------
function ActivateKeypadWindow(Keypad KPad, bool bHacked)
{
   KPad.ActivateKeypadWindow(Self, bHacked);
}

function KeypadRunUntriggers(Keypad KPad)
{
   KPad.RunUntriggers(Self);
}

function KeypadRunEvents(Keypad KPad, bool bSuccess)
{
   KPad.RunEvents(Self, bSuccess);
}

function KeypadToggleLocks(Keypad KPad)
{
   KPad.ToggleLocks(Self);
}

// ----------------------------------------------------------------------
// Multiplayer computer functions
// ----------------------------------------------------------------------

//server->client (computer to frobber)
function InvokeComputerScreen(Computers computerToActivate, float CompHackTime, float ServerLevelTime)
{
   local NetworkTerminal termwindow;
   local DeusExRootWindow root;

   computerToActivate.LastHackTime = CompHackTime + (Level.TimeSeconds - ServerLevelTime);

   ActiveComputer = ComputerToActivate;

   //only allow for clients or standalone
   if ((Level.NetMode != NM_Standalone) && (!PlayerIsClient()))
   {
      ActiveComputer = None;
      CloseComputerScreen(computerToActivate);
      return;
   }

   root = DeusExRootWindow(rootWindow);
   if (root != None)
   {
      termwindow = NetworkTerminal(root.InvokeUIScreen(computerToActivate.terminalType, True));
      if (termwindow != None)
      {
            computerToActivate.termwindow = termwindow;
         termWindow.SetCompOwner(computerToActivate);
         // If multiplayer, start hacking if there are no users
         if ((Level.NetMode != NM_Standalone) && (!termWindow.bHacked) && (computerToActivate.NumUsers() == 0) && 
             (termWindow.winHack != None) && (termWindow.winHack.btnHack != None))
         {
            termWindow.winHack.StartHack();
            termWindow.winHack.btnHack.SetSensitivity(False);
            termWindow.FirstScreen=None;
         }
         termWindow.ShowFirstScreen();
      }
   }
   if ((termWindow == None)  || (root == None))
   {
      CloseComputerScreen(computerToActivate);
      ActiveComputer = None;
   }
}


// CloseThisComputer is for the client (used at the end of a mp match)

function CloseThisComputer( Computers comp )
{
    if ((comp != None) && ( comp.termwindow != None ))
        comp.termwindow.CloseScreen("EXIT");
}

//client->server (window to player)
function CloseComputerScreen(Computers computerToClose)
{
   computerToClose.CloseOut();
}

//client->server (window to player)
function SetComputerHackTime(Computers computerToSet, float HackTime, float ClientLevelTime)
{
   computerToSet.lastHackTime = HackTime + (Level.TimeSeconds - ClientLevelTime);
}

//client->server (window to player)
function UpdateCameraRotation(SecurityCamera camera, Rotator rot)
{
    camera.DesiredRotation = rot;
}

//client->server (window to player)
function ToggleCameraState(SecurityCamera cam, ElectronicDevices compOwner)
{
   if (cam.bActive)
   {
      cam.UnTrigger(compOwner, self);   
      cam.team = -1;
   }
   else            
   {
      MakeCameraAlly(cam);
      cam.Trigger(compOwner, self);
   }
         
   // Make sure the camera isn't in bStasis=True
   // so it responds to our every whim.
   cam.bStasis = False;         
}

//client->server (window to player)
function SetTurretState(AutoTurret turret, bool bActive, bool bDisabled)
{
   turret.bActive   = bActive;
   turret.bDisabled = bDisabled;
    turret.bComputerReset = False;
}

//client->server (window to player)
function SetTurretTrackMode(ComputerSecurity computer, AutoTurret turret, bool bTrackPlayers, bool bTrackPawns)
{
    local String str;

   turret.bTrackPlayersOnly = bTrackPlayers;
   turret.bTrackPawnsOnly   = bTrackPawns;
    turret.bComputerReset = False;

   //in multiplayer, behave differently
   //set the safe target to ourself.
   if (Level.NetMode != NM_Standalone)
   {
      //we abuse the names of the booleans here.
        turret.SetSafeTarget( Self );

        if (Role == ROLE_Authority)
        {
            if ( TeamDMGame(DXGame) != None )
            {
                computer.team = PlayerReplicationInfo.team;
                turret.team = PlayerReplicationInfo.Team;
                if ( !turret.bDisabled )
                {
                    str = TakenOverString $ turret.titleString $ ".";
                    TeamSay( str );
                }
            }
            else
            {
                computer.team = PlayerReplicationInfo.PlayerID;
                turret.team = PlayerReplicationInfo.PlayerID;
            }
        }
   }
}

//client->server (window to player)
function MakeCameraAlly(SecurityCamera camera)
{
   Camera.SafeTarget = Self;
   if (Level.Game.IsA('TeamDMGame'))   
      Camera.Team = PlayerReplicationInfo.Team;
   else
      Camera.Team = PlayerReplicationInfo.PlayerID;
}

//client->server (window to player)
function PunishDetection(int DamageAmount)
{
   if (DamageAmount > 0)
      TakeDamage(DamageAmount, None, vect(0,0,0), vect(0,0,0), 'EMP');  
}

// ----------------------------------------------------------------------
// AddDamageDisplay()
//
// Turn on the correct damage type icon on the HUD
// Note that these icons naturally fade out after a few seconds,
// so there is no need to turn them off
// ----------------------------------------------------------------------

function AddDamageDisplay(name damageType, vector hitOffset)
{
    DeusExRootWindow(rootWindow).hud.damageDisplay.AddIcon(damageType, hitOffset);
}

// ----------------------------------------------------------------------
// SetDamagePercent()
//
// Set the percentage amount of damage that's being absorbed
// ----------------------------------------------------------------------

function SetDamagePercent(float percent)
{
    DeusExRootWindow(rootWindow).hud.damageDisplay.SetPercent(percent);
}

// ----------------------------------------------------------------------
// default sound functions
// ----------------------------------------------------------------------

// ----------------------------------------------------------------------
// PlayBodyThud()
//
// this is called by MESH NOTIFY
// ----------------------------------------------------------------------

function PlayBodyThud()                                                 
{
    PlaySound(sound'BodyThud', SLOT_Interact);
}

// ----------------------------------------------------------------------
// GetWallMaterial()
//
// gets the name of the texture group that we are facing
// ----------------------------------------------------------------------

function name GetWallMaterial(out vector wallNormal)
{
    local vector EndTrace, HitLocation, HitNormal;
    local actor target;
    local int texFlags, grabDist;
    local name texName, texGroup;

    // if we are falling, then increase our grabbing distance
    if (Physics == PHYS_Falling)
        grabDist = 3.0;
    else
        grabDist = 1.5;

    // trace out in front of us
    EndTrace = Location + (Vector(Rotation) * CollisionRadius * grabDist);

    foreach TraceTexture(class'Actor', target, texName, texGroup, texFlags, HitLocation, HitNormal, EndTrace)
    {
        if ((target == Level) || target.IsA('Mover'))
            break;
    }

    wallNormal = HitNormal;

    return texGroup;
}

// ----------------------------------------------------------------------
// 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
// ----------------------------------------------------------------------

simulated function PlayFootStep()
{
    local Sound stepSound;
    local float rnd;
    local float speedFactor, massFactor;
    local float volume, pitch, range;
    local float radius, mult;
    local float volumeMultiplier;
    local DeusExPlayer pp;
    local bool bOtherPlayer;

    // Only do this on ourself, since this takes into account aug stealth and such
    if ( Level.NetMode != NM_StandAlone )
        pp = DeusExPlayer( GetPlayerPawn() );

    if ( pp != Self )
        bOtherPlayer = True;
    else
        bOtherPlayer = False;

    rnd = FRand();

    volumeMultiplier = 1.0;
    if (IsInState('PlayerSwimming') || (Physics == PHYS_Swimming))
    {
        volumeMultiplier = 0.5;
        if (rnd < 0.5)
            stepSound = Sound'Swimming';
        else
            stepSound = Sound'Treading';
    }
    else if (FootRegion.Zone.bWaterZone)
    {
        volumeMultiplier = 1.0;
        if (rnd < 0.33)
            stepSound = Sound'WaterStep1';
        else if (rnd < 0.66)
            stepSound = Sound'WaterStep2';
        else
            stepSound = Sound'WaterStep3';
    }
    else
    {
        switch(FloorMaterial)
        {
            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;
        }
    }

    // compute sound volume, range and pitch, based on mass and speed
    if (IsInState('PlayerSwimming') || (Physics == PHYS_Swimming))
        speedFactor = WaterSpeed/180.0;
    else
        speedFactor = VSize(Velocity)/180.0;

    massFactor  = Mass/150.0;
    radius      = 375.0;
    volume      = (speedFactor+0.2) * massFactor;
    range       = radius * volume;
    pitch       = (volume+0.5);
    volume      = FClamp(volume, 0, 1.0) * 0.5;     // Hack to compensate for increased footstep volume.											
    range       = FClamp(range, 0.01, radius*4);
    pitch       = FClamp(pitch, 1.0, 1.5);

    // AugStealth decreases our footstep volume
    volume *= RunSilentValue;

    if ( Level.NetMode == NM_Standalone )
        PlaySound(stepSound, SLOT_Interact, volume, , range, pitch);
    else    // special case for multiplayer
    {
        if ( !bIsWalking )
        {
            // Tone down player's own footsteps
            if ( !bOtherPlayer )
            {
                volume *= 0.33;
                PlaySound(stepSound, SLOT_Interact, volume, , range, pitch);
            }
            else // Exagerate other players sounds (range slightly greater than distance you see with vision aug)
            {
                volume *= 2.0;
                range = (class'AugVision'.Default.mpAugValue * 1.2);
                volume = FClamp(volume, 0, 1.0);
                PlaySound(stepSound, SLOT_Interact, volume, , range, pitch);
            }
        }
    }
    AISendEvent('LoudNoise', EAITYPE_Audio, volume*volumeMultiplier, range*volumeMultiplier);
}

// ----------------------------------------------------------------------
// IsHighlighted()
//
// checks to see if we should highlight this actor
// ----------------------------------------------------------------------

function bool IsHighlighted(actor A)
{
    if (bBehindView)
        return False;

    if (A != None)
    {
        if (A.bDeleteMe || A.bHidden)
            return False;

        if (A.IsA('Pawn'))
        {
            if (!bNPCHighlighting)
                return False;
        }

        if (A.IsA('DeusExMover') && !DeusExMover(A).bHighlight)
            return False;
        else if (A.IsA('Mover') && !A.IsA('DeusExMover'))
            return False;
        else if (A.IsA('DeusExDecoration') && !DeusExDecoration(A).bHighlight)
            return False;
        else if (A.IsA('DeusExCarcass') && !DeusExCarcass(A).bHighlight)
            return False;
        else if (A.IsA('ThrownProjectile') && !ThrownProjectile(A).bHighlight)
            return False;
        else if (A.IsA('DeusExProjectile') && !DeusExProjectile(A).bStuck)
            return False;
        else if (A.IsA('ScriptedPawn') && !ScriptedPawn(A).bHighlight)
            return False;
    }

    return True;
}

// ----------------------------------------------------------------------
// IsFrobbable()
//
// is this actor frobbable?
// ----------------------------------------------------------------------

function bool IsFrobbable(actor A)
{
    if (!A.bHidden)
        if (A.IsA('Mover') || A.IsA('DeusExDecoration') || A.IsA('Inventory') ||
            A.IsA('ScriptedPawn') || A.IsA('DeusExCarcass') || A.IsA('DeusExProjectile'))
            return True;

    return False;
}

// ----------------------------------------------------------------------
// HighlightCenterObject()
//
// checks to see if an object can be frobbed, if so, then highlight it
// ----------------------------------------------------------------------

function HighlightCenterObject()
{
    local Actor target, smallestTarget;
    local Vector HitLoc, HitNormal, StartTrace, EndTrace;
    local DeusExRootWindow root;
    local float minSize;
    local bool bFirstTarget;

    if (IsInState('Dying'))
        return;

    root = DeusExRootWindow(rootWindow);

    // only do the trace every tenth of a second
    if (FrobTime >= 0.1)
    {
        // figure out how far ahead we should trace
        StartTrace = Location;
        EndTrace = Location + (Vector(ViewRotation) * MaxFrobDistance);

        // adjust for the eye height
        StartTrace.Z += BaseEyeHeight;
        EndTrace.Z += BaseEyeHeight;

        smallestTarget = None;
        minSize = 99999;
        bFirstTarget = True;

        // find the object that we are looking at
        // make sure we don't select the object that we're carrying
        // use the last traced object as the target...this will handle
        // smaller items under larger items for example
        // ScriptedPawns always have precedence, though
        foreach TraceActors(class'Actor', target, HitLoc, HitNormal, EndTrace, StartTrace)
        {
            if (IsFrobbable(target) && (target != CarriedDecoration))
            {
                if (target.IsA('ScriptedPawn'))
                {
                    smallestTarget = target;
                    break;
                }
                else if (target.IsA('Mover') && bFirstTarget)
                {
                    smallestTarget = target;
                    break;
                }
                else if (target.CollisionRadius < minSize)
                {
                    minSize = target.CollisionRadius;
                    smallestTarget = target;
                    bFirstTarget = False;
                }
            }
        }
        FrobTarget = smallestTarget;

        // reset our frob timer
        FrobTime = 0;
    }
}

// ----------------------------------------------------------------------
// Landed()
//
// copied from Engine.PlayerPawn new landing code for Deus Ex
// zero damage if falling from 15 feet or less
// scaled damage from 15 to 60 feet
// death over 60 feet
// ----------------------------------------------------------------------

function Landed(vector HitNormal)
{
    local vector legLocation;
    local int augLevel;
    local float augReduce, dmg;

    //Note - physics changes type to PHYS_Walking by default for landed pawns
    PlayLanded(Velocity.Z);
    if (Velocity.Z < -1.4 * JumpZ)
    {
        MakeNoise(-0.5 * Velocity.Z/(FMax(JumpZ, 150.0)));
        if ((Velocity.Z < -700) && (ReducedDamageType != 'All'))
            if ( Role == ROLE_Authority )
            {
                // check our jump augmentation and reduce falling damage if we have it
                // jump augmentation doesn't exist anymore - use Speed instaed
                // reduce an absolute amount of damage instead of a relative amount
                augReduce = 0;
                if (AugmentationSystem != None)
                {
                    augLevel = AugmentationSystem.GetClassLevel(class'AugSpeed');
                    if (augLevel >= 0)
                        augReduce = 15 * (augLevel+1);
                }

                dmg = Max((-0.16 * (Velocity.Z + 700)) - augReduce, 0);
                legLocation = Location + vect(-1,0,-1);         // damage left leg
                TakeDamage(dmg, None, legLocation, vect(0,0,0), 'fell');

                legLocation = Location + vect(1,0,-1);          // damage right leg
                TakeDamage(dmg, None, legLocation, vect(0,0,0), 'fell');

                dmg = Max((-0.06 * (Velocity.Z + 700)) - augReduce, 0);
                legLocation = Location + vect(0,0,1);           // damage torso
                TakeDamage(dmg, None, legLocation, vect(0,0,0), 'fell');
            }
    }
    else if ( (Level.Game != None) && (Level.Game.Difficulty > 1) && (Velocity.Z > 0.5 * JumpZ) )
        MakeNoise(0.1 * Level.Game.Difficulty);             
    bJustLanded = true;
}

// ----------------------------------------------------------------------
// SupportActor()
//
// Copied directly from ScriptedPawn.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;

    zVelocity    = standingActor.Velocity.Z;
    standingMass = FMax(1, standingActor.Mass);
    baseMass     = FMax(1, Mass);
    damagePoint  = Location + vect(0,0,1)*(CollisionHeight-1);
    damage       = (1 - (standingMass/baseMass) * (zVelocity/100));

    // Have we been stomped?
    if ((zVelocity*standingMass < -7500) && (damage > 0))
        TakeDamage(damage, standingActor.Instigator, damagePoint, 0.2*standingActor.Velocity, 'stomped');

    // Bounce the actor off the player
    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()
//
// copied from Engine.PlayerPawn
// modified to let carcasses have inventories
// ----------------------------------------------------------------------

function Carcass SpawnCarcass()
{
    local DeusExCarcass carc;
    local Inventory item;
    local Vector loc;

    // don't spawn a carcass if we've been gibbed
    if (Health < -80)
      return None;

    carc = DeusExCarcass(Spawn(CarcassType));
    if (carc != None)
    {
        carc.Initfor(self);

        // move it down to the ground
        loc = Location;
        loc.z -= CollisionHeight;
        loc.z += carc.CollisionHeight;
        carc.SetLocation(loc);

        if (Player != None)
            carc.bPlayerCarcass = true;
        MoveTarget = carc; //for Player 3rd person views

        // give the carcass the player's inventory
        for (item=Inventory; item!=None; item=Inventory)
        {
            DeleteInventory(item);
            carc.AddInventory(item);
        }
    }

    return carc;
}

// ----------------------------------------------------------------------
// Reloading()
//
// Called when one of the player's weapons is reloading
// ----------------------------------------------------------------------

function Reloading(DeusExWeapon weapon, float reloadTime)
{
    if (!IsLeaning() && !bIsCrouching && (Physics != PHYS_Swimming) && !IsInState('Dying'))
        PlayAnim('Reload', 1.0 / reloadTime, 0.1);
}
function DoneReloading(DeusExWeapon weapon);

// ----------------------------------------------------------------------
// HealPlayer()
// ----------------------------------------------------------------------

function int HealPlayer(int baseHealPoints, optional Bool bUseMedicineSkill)
{
    local float mult;
    local int adjustedHealAmount, aha2, tempaha;
    local int origHealAmount;
    local float dividedHealAmount;

    if (bUseMedicineSkill)
        adjustedHealAmount = CalculateSkillHealAmount(baseHealPoints);
    else
        adjustedHealAmount = baseHealPoints;

    origHealAmount = adjustedHealAmount;

    if (adjustedHealAmount > 0)
    {
        if (bUseMedicineSkill)
            PlaySound(sound'MedicalHiss', SLOT_None,,, 256);

        // Heal by 3 regions via multiplayer game
        if (( Level.NetMode == NM_DedicatedServer ) || ( Level.NetMode == NM_ListenServer ))
        {
         // DEUS_EX AMSD If legs broken, heal them a little bit first
         if (HealthLegLeft == 0)
         {
            aha2 = adjustedHealAmount;
            if (aha2 >= 5)
               aha2 = 5;
            tempaha = aha2;
            adjustedHealAmount = adjustedHealAmount - aha2;
            HealPart(HealthLegLeft, aha2);
            HealPart(HealthLegRight,tempaha);
                mpMsgServerFlags = mpMsgServerFlags & (~MPSERVERFLAG_LostLegs);
         }
            HealPart(HealthHead, adjustedHealAmount);

            if ( adjustedHealAmount > 0 )
            {
                aha2 = adjustedHealAmount;
                HealPart(HealthTorso, aha2);
                aha2 = adjustedHealAmount;
                HealPart(HealthArmRight,aha2);
                HealPart(HealthArmLeft, adjustedHealAmount);
            }
            if ( adjustedHealAmount > 0 )
            {
                aha2 = adjustedHealAmount;
                HealPart(HealthLegRight, aha2);
                HealPart(HealthLegLeft, adjustedHealAmount);
            }
        }
        else
        {
            HealPart(HealthHead, adjustedHealAmount);
            HealPart(HealthTorso, adjustedHealAmount);
            HealPart(HealthLegRight, adjustedHealAmount);
            HealPart(HealthLegLeft, adjustedHealAmount);
            HealPart(HealthArmRight, adjustedHealAmount);
            HealPart(HealthArmLeft, adjustedHealAmount);
        }

        GenerateTotalHealth();

        adjustedHealAmount = origHealAmount - adjustedHealAmount;

        if (origHealAmount == baseHealPoints)
        {
            if (adjustedHealAmount == 1)
                ClientMessage(Sprintf(HealedPointLabel, adjustedHealAmount));
            else
                ClientMessage(Sprintf(HealedPointsLabel, adjustedHealAmount));
        }
        else
        {
            ClientMessage(Sprintf(HealedPointsLabel, adjustedHealAmount));
        }
    }

    return adjustedHealAmount;
}

// ----------------------------------------------------------------------
// ChargePlayer()
// ----------------------------------------------------------------------

function int ChargePlayer(int baseChargePoints)
{
    local int chargedPoints;

    chargedPoints = Min(EnergyMax - Int(Energy), baseChargePoints);

    Energy += chargedPoints;

    return chargedPoints;   
}

// ----------------------------------------------------------------------
// CalculateSkillHealAmount()
// ----------------------------------------------------------------------

function int CalculateSkillHealAmount(int baseHealPoints)
{
    local float mult;
    local int adjustedHealAmount;

    // check skill use
    if (SkillSystem != None)
    {
        mult = SkillSystem.GetSkillLevelValue(class'SkillMedicine');

        // apply the skill
        adjustedHealAmount = baseHealPoints * mult;
    }

    return adjustedHealAmount;
}

// ----------------------------------------------------------------------
// HealPart()
// ----------------------------------------------------------------------

function HealPart(out int points, out int amt)
{
    local int spill;

    points += amt;
    spill = points - 100;
    if (spill > 0)
        points = 100;
    else
        spill = 0;

    amt = spill;
}

// ----------------------------------------------------------------------
// HandleWalking()
//
// subclassed from PlayerPawn so we can control run/walk defaults
// ----------------------------------------------------------------------

function HandleWalking()
{
    Super.HandleWalking();

    if (bAlwaysRun)
        bIsWalking = (bRun != 0) || (bDuck != 0); 
    else
        bIsWalking = (bRun == 0) || (bDuck != 0); 

    // handle the toggle walk key
    if (bToggleWalk)
        bIsWalking = !bIsWalking;

    if (bToggleCrouch)
    {
        if (!bCrouchOn && !bWasCrouchOn && (bDuck != 0))
        {
            bCrouchOn = True;
        }
        else if (bCrouchOn && !bWasCrouchOn && (bDuck == 0))
        {
            bWasCrouchOn = True;
        }
        else if (bCrouchOn && bWasCrouchOn && (bDuck == 0) && (lastbDuck != 0))
        {
            bCrouchOn = False;
            bWasCrouchOn = False;
        }

        if (bCrouchOn)
        {
            bIsCrouching = True;
            bDuck = 1;
        }

        lastbDuck = bDuck;
    }
}

// ----------------------------------------------------------------------
// DoJump()
// 
// copied from Engine.PlayerPawn
// Modified to let you jump if you are carrying something rather light
// You can also jump if you are crouching, just at a much lower height
// ----------------------------------------------------------------------

function DoJump( optional float F )
{
    local DeusExWeapon w;
    local float scaleFactor, augLevel;

    if ((CarriedDecoration != None) && (CarriedDecoration.Mass > 20))
        return;
    else if (bForceDuck || IsLeaning())
        return;

    if (Physics == PHYS_Walking)
    {
        if ( Role == ROLE_Authority )
            PlaySound(JumpSound, SLOT_None, 1.5, true, 1200, 1.0 - 0.2*FRand() );
        if ( (Level.Game != None) && (Level.Game.Difficulty > 0) )
            MakeNoise(0.1 * Level.Game.Difficulty);
        PlayInAir();

        Velocity.Z = JumpZ;

        if ( Level.NetMode != NM_Standalone )
        {
         if (AugmentationSystem == None)
            augLevel = -1.0;
         else           
            augLevel = AugmentationSystem.GetAugLevelValue(class'AugSpeed');
            w = DeusExWeapon(InHand);
            if ((augLevel != -1.0) && ( w != None ) && ( w.Mass > 30.0))
            {
                scaleFactor = 1.0 - FClamp( ((w.Mass - 30.0)/55.0), 0.0, 0.5 );
                Velocity.Z *= scaleFactor;
            }
        }
        
        // reduce the jump velocity if you are crouching
//		if (bIsCrouching)
//			Velocity.Z *= 0.9;

        if ( Base != Level )
            Velocity.Z += Base.Velocity.Z;
        SetPhysics(PHYS_Falling);
        if ( bCountJumps && (Role == ROLE_Authority) )
            Inventory.OwnerJumped();
    }
}

function bool IsLeaning()
{
    return (curLeanDist != 0);
}

// ----------------------------------------------------------------------
// SetBasedPawnSize()
// ----------------------------------------------------------------------

function bool SetBasedPawnSize(float newRadius, float newHeight)
{
    local float  oldRadius, oldHeight;
    local bool   bSuccess;
    local vector centerDelta, lookDir, upDir;
    local float  deltaEyeHeight;
    local Decoration savedDeco;

    if (newRadius < 0)
        newRadius = 0;
    if (newHeight < 0)
        newHeight = 0;

    oldRadius = CollisionRadius;
    oldHeight = CollisionHeight;

    if ( Level.NetMode == NM_Standalone )
    {
        if ((oldRadius == newRadius) && (oldHeight == newHeight))
            return true;
    }

    centerDelta    = vect(0, 0, 1)*(newHeight-oldHeight);
    deltaEyeHeight = GetDefaultCollisionHeight() - Default.BaseEyeHeight;

    if ( Level.NetMode != NM_Standalone )
    {
        if ((oldRadius == newRadius) && (oldHeight == newHeight) && (BaseEyeHeight == newHeight - deltaEyeHeight))
            return true;
    }

    if (CarriedDecoration != None)
        savedDeco = CarriedDecoration;

    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)
    {
        // make sure we don't lose our carried decoration
        if (savedDeco != None)
        {
            savedDeco.SetPhysics(PHYS_None);
            savedDeco.SetBase(Self);
            savedDeco.SetCollision(False, False, False);

            // reset the decoration's location
            lookDir = Vector(Rotation);
            lookDir.Z = 0;              
            upDir = vect(0,0,0);
            upDir.Z = CollisionHeight / 2;      // put it up near eye level
            savedDeco.SetLocation(Location + upDir + (0.5 * CollisionRadius + CarriedDecoration.CollisionRadius) * lookDir);
        }

//		PrePivotOffset  = vect(0, 0, 1)*(GetDefaultCollisionHeight()-newHeight);
        PrePivot        -= centerDelta;
//		DesiredPrePivot -= centerDelta;
        BaseEyeHeight   = newHeight - deltaEyeHeight;

        // Complaints that eye height doesn't seem like your crouching in multiplayer
        if (( Level.NetMode != NM_Standalone ) && (bIsCrouching || bForceDuck) )
            EyeHeight       -= (centerDelta.Z * 2.5);
        else
            EyeHeight       -= centerDelta.Z;
    }
    return (bSuccess);
}

// ----------------------------------------------------------------------
// ResetBasedPawnSize()
// ----------------------------------------------------------------------

function bool ResetBasedPawnSize()
{
    return SetBasedPawnSize(Default.CollisionRadius, GetDefaultCollisionHeight());
}

// ----------------------------------------------------------------------
// GetDefaultCollisionHeight()
// ----------------------------------------------------------------------

function float GetDefaultCollisionHeight()
{
    return (Default.CollisionHeight-4.5);
}

// ----------------------------------------------------------------------
// GetCurrentGroundSpeed()
// ----------------------------------------------------------------------

function float GetCurrentGroundSpeed()
{
    local float augValue, speed;

    // Remove this later and find who's causing this to Access None MB
    if ( AugmentationSystem == None )
        return 0;

   augValue = AugmentationSystem.GetAugLevelValue(class'AugSpeed');

    if (augValue == -1.0)
        augValue = 1.0;

    if (( Level.NetMode != NM_Standalone ) && Self.IsA('Human') )
        speed = Human(Self).mpGroundSpeed * augValue;
    else
        speed = Default.GroundSpeed * augValue;

    return speed;
}

// ----------------------------------------------------------------------
// CreateDrone
// ----------------------------------------------------------------------
function CreateDrone()
{
    local Vector loc;

    loc = (2.0 + class'SpyDrone'.Default.CollisionRadius + CollisionRadius) * Vector(ViewRotation);
    loc.Z = BaseEyeHeight;
    loc += Location;
    aDrone = Spawn(class'SpyDrone', Self,, loc, ViewRotation);
    if (aDrone != None)
    {
        aDrone.Speed = 3 * spyDroneLevelValue;
        aDrone.MaxSpeed = 3 * spyDroneLevelValue;
        aDrone.Damage = 5 * spyDroneLevelValue;
        aDrone.blastRadius = 8 * spyDroneLevelValue;
        // window construction now happens in Tick()
    }
}

// ----------------------------------------------------------------------
// MoveDrone
// ----------------------------------------------------------------------

simulated function MoveDrone( float DeltaTime, Vector loc )
{
    // if the wanted velocity is zero, apply drag so we slow down gradually
    if (VSize(loc) == 0)
   {
      aDrone.Velocity *= 0.9;
   }
    else
   {
      aDrone.Velocity += deltaTime * aDrone.MaxSpeed * loc;
   }

    // add slight bobbing
   // DEUS_EX AMSD Only do the bobbing in singleplayer, we want stationary drones stationary.
   if (Level.Netmode == NM_Standalone)  
      aDrone.Velocity += deltaTime * Sin(Level.TimeSeconds * 2.0) * vect(0,0,1);
}

function ServerUpdateLean( Vector desiredLoc )
{
    local Vector gndCheck, traceSize, HitNormal, HitLocation;
    local Actor HitActor, HitActorGnd;

    // First check to see if anything is in the way
    traceSize.X = CollisionRadius;
    traceSize.Y = CollisionRadius;
    traceSize.Z = CollisionHeight;
    HitActor = Trace( HitLocation, HitNormal, desiredLoc, Location, True, traceSize );

    // Make we don't lean off the edge of something
    if ( HitActor == None ) // Don't bother if we're going to fail to set anyway
    {
        gndCheck = desiredLoc - vect(0,0,1) * CollisionHeight;
        HitActorGnd = Trace( HitLocation, HitNormal, gndCheck, desiredLoc, True, traceSize );
    }

    if ( (HitActor == None) && (HitActorGnd != None) )
        SetLocation( desiredLoc );

//	SetRotation( rot );
}

// ----------------------------------------------------------------------
// state PlayerWalking
// ----------------------------------------------------------------------

state PlayerWalking
{
    // lets us affect the player's movement
    function ProcessMove ( float DeltaTime, vector newAccel, eDodgeDir DodgeMove, rotator DeltaRot)
    {
        local int newSpeed, defSpeed;
        local name mat;
        local vector HitLocation, HitNormal, checkpoint, downcheck;
        local Actor HitActor, HitActorDown;
        local bool bCantStandUp;
        local Vector loc, traceSize;
        local float alpha, maxLeanDist;
        local float legTotal, weapSkill;

        // if the spy drone augmentation is active
        if (bSpyDroneActive)
        {
            if ( aDrone != None ) 
            {
                // put away whatever is in our hand
                if (inHand != None)
                    PutInHand(None);

                // make the drone's rotation match the player's view
                aDrone.SetRotation(ViewRotation);

                // move the drone
                loc = Normal((aUp * vect(0,0,1) + aForward * vect(1,0,0) + aStrafe * vect(0,1,0)) >> ViewRotation);

                // opportunity for client to translate movement to server
                MoveDrone( DeltaTime, loc );

                // freeze the player
                Velocity = vect(0,0,0);
            }
            return;
        }

        defSpeed = GetCurrentGroundSpeed();

      // crouching makes you two feet tall
        if (bIsCrouching || bForceDuck)
        {
            if ( Level.NetMode != NM_Standalone )
                SetBasedPawnSize(Default.CollisionRadius, 30.0);
            else
                SetBasedPawnSize(Default.CollisionRadius, 16);

            // check to see if we could stand up if we wanted to
            checkpoint = Location;
            // check normal standing height
            checkpoint.Z = checkpoint.Z - CollisionHeight + 2 * GetDefaultCollisionHeight();
            traceSize.X = CollisionRadius;
            traceSize.Y = CollisionRadius;
            traceSize.Z = 1;
            HitActor = Trace(HitLocation, HitNormal, checkpoint, Location, True, traceSize);
            if (HitActor == None)
                bCantStandUp = False;
            else
                bCantStandUp = True;
        }
        else
        {
         // DEUS_EX AMSD Changed this to grab defspeed, because GetCurrentGroundSpeed takes 31k cycles to run.
            GroundSpeed = defSpeed;

            // make sure the collision height is fudged for the floor problem - CNN
            if (!IsLeaning())
            {
                ResetBasedPawnSize();
            }
        }

        if (bCantStandUp)
            bForceDuck = True;
        else
            bForceDuck = False;

        // if the player's legs are damaged, then reduce our speed accordingly
        newSpeed = defSpeed;

        if ( Level.NetMode == NM_Standalone )
        {
            if (HealthLegLeft < 1)
                newSpeed -= (defSpeed/2) * 0.25;
            else if (HealthLegLeft < 34)
                newSpeed -= (defSpeed/2) * 0.15;
            else if (HealthLegLeft < 67)
                newSpeed -= (defSpeed/2) * 0.10;

            if (HealthLegRight < 1)
                newSpeed -= (defSpeed/2) * 0.25;
            else if (HealthLegRight < 34)
                newSpeed -= (defSpeed/2) * 0.15;
            else if (HealthLegRight < 67)
                newSpeed -= (defSpeed/2) * 0.10;

            if (HealthTorso < 67)
                newSpeed -= (defSpeed/2) * 0.05;
        }

        // let the player pull themselves along with their hands even if both of
        // their legs are blown off
        if ((HealthLegLeft < 1) && (HealthLegRight < 1))
        {
            newSpeed = defSpeed * 0.8;
            bIsWalking = True;
            bForceDuck = True;
        }
        // make crouch speed faster than normal
        else if (bIsCrouching || bForceDuck)
        {
//			newSpeed = defSpeed * 1.8;		// DEUS_EX CNN - uncomment to speed up crouch
            bIsWalking = True;
        }

        // CNN - Took this out because it sucks ASS!
        // if the legs are seriously damaged, increase the head bob
        // (unless the player has turned it off)
/*      if (Bob > 0.0)
        {
            legTotal = (HealthLegLeft + HealthLegRight) / 2.0;
            if (legTotal < 50)
                Bob = Default.Bob * FClamp(0.05*(70 - legTotal), 1.0, 3.0);
            else
                Bob = Default.Bob;
        }
*/
        // slow the player down if he's carrying something heavy
        // Like a DEAD BODY!  AHHHHHH!!!
        if (CarriedDecoration != None)
        {
            newSpeed -= CarriedDecoration.Mass * 2;
        }
        // don't slow the player down if he's skilled at the corresponding weapon skill  
        else if ((DeusExWeapon(Weapon) != None) && (Weapon.Mass > 30) && (DeusExWeapon(Weapon).GetWeaponSkill() > -0.25) && (Level.NetMode==NM_Standalone))
        {
            bIsWalking = True;
            newSpeed = defSpeed;
        }
        else if ((inHand != None) && inHand.IsA('POVCorpse'))
        {
            newSpeed -= inHand.Mass * 3;
        }

        // Multiplayer movement adjusters
        if ( Level.NetMode != NM_Standalone )
        {
            if ( Weapon != None )
            {
                weapSkill = DeusExWeapon(Weapon).GetWeaponSkill();
                // Slow down heavy weapons in multiplayer
                if ((DeusExWeapon(Weapon) != None) && (Weapon.Mass > 30) )
                {
                    newSpeed = defSpeed;
                    newSpeed -= ((( Weapon.Mass - 30.0 ) / (class'WeaponGEPGun'.Default.Mass - 30.0 )) * (0.70 + weapSkill) * defSpeed );
                }
                // Slow turn rate of GEP gun in multiplayer to discourage using it as the most effective close quarters weapon
                if ((WeaponGEPGun(Weapon) != None) && (!WeaponGEPGun(Weapon).bZoomed))
                    TurnRateAdjuster = FClamp( 0.20 + -(weapSkill*0.5), 0.25, 1.0 );
                else
                    TurnRateAdjuster = 1.0;
            }
            else
                TurnRateAdjuster = 1.0;
        }

        // if we are moving really slow, force us to walking
        if ((newSpeed <= defSpeed / 3) && !bForceDuck)
        {
            bIsWalking = True;
            newSpeed = defSpeed;
        }

        // if we are moving backwards, we should move slower
      // DEUS_EX AMSD Turns out this wasn't working right in multiplayer, I have a fix
      // for it, but it would change all our balance.
        if ((aForward < 0) && (Level.NetMode == NM_Standalone))
            newSpeed *= 0.65;

        GroundSpeed = FMax(newSpeed, 100);

        // if we are moving or crouching, we can't lean
        // uncomment below line to disallow leaning during crouch

            if ((VSize(Velocity) < 10) && (aForward == 0))      // && !bIsCrouching && !bForceDuck)
                bCanLean = True;
            else
                bCanLean = False;

            // check leaning buttons (axis aExtra0 is used for leaning)
            maxLeanDist = 40;

            if (IsLeaning())
            {
                if ( PlayerIsClient() || (Level.NetMode == NM_Standalone) )
                    ViewRotation.Roll = curLeanDist * 20;
            
                if (!bIsCrouching && !bForceDuck)
                    SetBasedPawnSize(CollisionRadius, GetDefaultCollisionHeight() - Abs(curLeanDist) / 3.0);
            }
            if (bCanLean && (aExtra0 != 0))
            {
                // lean
                DropDecoration();       // drop the decoration that we are carrying
                if (AnimSequence != 'CrouchWalk')
                    PlayCrawling();

                alpha = maxLeanDist * aExtra0 * 2.0 * DeltaTime;

                loc = vect(0,0,0);
                loc.Y = alpha;
                if (Abs(curLeanDist + alpha) < maxLeanDist)
                {
                    // check to make sure the destination not blocked
                    checkpoint = (loc >> Rotation) + Location;
                    traceSize.X = CollisionRadius;
                    traceSize.Y = CollisionRadius;
                    traceSize.Z = CollisionHeight;
                    HitActor = Trace(HitLocation, HitNormal, checkpoint, Location, True, traceSize);

                    // check down as well to make sure there's a floor there
                    downcheck = checkpoint - vect(0,0,1) * CollisionHeight;
                    HitActorDown = Trace(HitLocation, HitNormal, downcheck, checkpoint, True, traceSize);
                    if ((HitActor == None) && (HitActorDown != None))
                    {
                        if ( PlayerIsClient() || (Level.NetMode == NM_Standalone))
                        {
                            SetLocation(checkpoint);
                            ServerUpdateLean( checkpoint );
                            curLeanDist += alpha;
                        }
                    }
                }
                else
                {
                    if ( PlayerIsClient() || (Level.NetMode == NM_Standalone) )
                        curLeanDist = aExtra0 * maxLeanDist;
                }
            }
            else if (IsLeaning())   //if (!bCanLean && IsLeaning())	// uncomment this to not hold down lean
            {
                // un-lean
                if (AnimSequence == 'CrouchWalk')
                    PlayRising();

                if ( PlayerIsClient() || (Level.NetMode == NM_Standalone))
                {
                    prevLeanDist = curLeanDist;
                    alpha = FClamp(7.0 * DeltaTime, 0.001, 0.9);
                    curLeanDist *= 1.0 - alpha;
                    if (Abs(curLeanDist) < 1.0)
                        curLeanDist = 0;
                }

                loc = vect(0,0,0);
                loc.Y = -(prevLeanDist - curLeanDist);

                // check to make sure the destination not blocked
                checkpoint = (loc >> Rotation) + Location;
                traceSize.X = CollisionRadius;
                traceSize.Y = CollisionRadius;
                traceSize.Z = CollisionHeight;
                HitActor = Trace(HitLocation, HitNormal, checkpoint, Location, True, traceSize);

                // check down as well to make sure there's a floor there
                downcheck = checkpoint - vect(0,0,1) * CollisionHeight;
                HitActorDown = Trace(HitLocation, HitNormal, downcheck, checkpoint, True, traceSize);
                if ((HitActor == None) && (HitActorDown != None))
                {
                    if ( PlayerIsClient() || (Level.NetMode == NM_Standalone))
                    {
                        SetLocation( checkpoint );
                        ServerUpdateLean( checkpoint );
                    }
                }
            }
        
        Super.ProcessMove(DeltaTime, newAccel, DodgeMove, DeltaRot);
    }

    function ZoneChange(ZoneInfo NewZone)
    {
        // if we jump into water, empty our hands
        if (NewZone.bWaterZone)
            DropDecoration();

        Super.ZoneChange(NewZone);
    }

    event PlayerTick(float deltaTime)
    {
        //DEUS_EX AMSD Additional updates
        //Because of replication delay, aug icons end up being a step behind generally.  So refresh them
        //every freaking tick.  
        RefreshSystems(deltaTime);

        DrugEffects(deltaTime);
        Bleed(deltaTime);
        HighlightCenterObject();


        UpdateDynamicMusic(deltaTime);
        UpdateWarrenEMPField(deltaTime);
      // DEUS_EX AMSD Move these funcions to a multiplayer tick
      // so that only that call gets propagated to the server.
      MultiplayerTick(deltaTime);
      // DEUS_EX AMSD For multiplayer...
        FrobTime += deltaTime;

        // save some texture info
        FloorMaterial = GetFloorMaterial();
        WallMaterial = GetWallMaterial(WallNormal);

        // Check if player has walked outside a first-person convo.
        CheckActiveConversationRadius();

        // Check if all the people involved in a conversation are 
        // still within a reasonable radius.
        CheckActorDistances();

        // handle poison
      //DEUS_EX AMSD Now handled in multiplayertick
        //UpdatePoison(deltaTime);

        // Update Time Played
        UpdateTimePlayed(deltaTime);

        Super.PlayerTick(deltaTime);
    }
}

// ----------------------------------------------------------------------
// state PlayerFlying
// ----------------------------------------------------------------------

state PlayerFlying
{
    function ZoneChange(ZoneInfo NewZone)
    {
        // if we jump into water, empty our hands
        if (NewZone.bWaterZone)
            DropDecoration();

        Super.ZoneChange(NewZone);
    }

    event PlayerTick(float deltaTime)
    {

        //DEUS_EX AMSD Additional updates
        //Because of replication delay, aug icons end up being a step behind generally.  So refresh them
        //every freaking tick.  
        RefreshSystems(deltaTime);

        DrugEffects(deltaTime);
        HighlightCenterObject();
        UpdateDynamicMusic(deltaTime);
      // DEUS_EX AMSD For multiplayer...
      MultiplayerTick(deltaTime);
        FrobTime += deltaTime;

        // Check if player has walked outside a first-person convo.
        CheckActiveConversationRadius();

        // Check if all the people involved in a conversation are 
        // still within a reasonable radius.
        CheckActorDistances();

        // Update Time Played
        UpdateTimePlayed(deltaTime);

        Super.PlayerTick(deltaTime);
    }
}

// ----------------------------------------------------------------------
// event HeadZoneChange
// ----------------------------------------------------------------------

event HeadZoneChange(ZoneInfo newHeadZone)
{
    local float mult, augLevel;
    
    // hack to get the zone's ambientsound working until Tim fixes it
    if (newHeadZone.AmbientSound != None)
        newHeadZone.SoundRadius = 255;
    if (HeadRegion.Zone.AmbientSound != None)
        HeadRegion.Zone.SoundRadius = 0;

    if (newHeadZone.bWaterZone && !HeadRegion.Zone.bWaterZone)
    {
        // make sure we're not crouching when we start swimming
        bIsCrouching = False;
        bCrouchOn = False;
        bWasCrouchOn = False;
        bDuck = 0;
        lastbDuck = 0;
        Velocity = vect(0,0,0);
        Acceleration = vect(0,0,0);
        mult = SkillSystem.GetSkillLevelValue(class'SkillSwimming');
        swimDuration = UnderWaterTime * mult;
        swimTimer = swimDuration;
        if (( Level.NetMode != NM_Standalone ) && Self.IsA('Human') )
        {
            if ( AugmentationSystem != None )
                augLevel = AugmentationSystem.GetAugLevelValue(class'AugAqualung');
            if ( augLevel == -1.0 )
                WaterSpeed = Human(Self).Default.mpWaterSpeed * mult;
            else
                WaterSpeed = Human(Self).Default.mpWaterSpeed * 2.0 * mult;
        }
        else
            WaterSpeed = Default.WaterSpeed * mult;
    }

    Super.HeadZoneChange(newHeadZone);
}

// ----------------------------------------------------------------------
// state PlayerSwimming
// ----------------------------------------------------------------------

state PlayerSwimming
{
    function GrabDecoration()
    {
        // we can't grab decorations underwater
    }

    function ZoneChange(ZoneInfo NewZone)
    {
        // if we jump into water, empty our hands
        if (NewZone.bWaterZone)
        {
            DropDecoration();
            if (bOnFire)
                ExtinguishFire();
        }

        Super.ZoneChange(NewZone);
    }

    event PlayerTick(float deltaTime)
    {
        local vector loc;

        //DEUS_EX AMSD Additional updates
        //Because of replication delay, aug icons end up being a step behind generally.  So refresh them
        //every freaking tick.  
        RefreshSystems(deltaTime);

        DrugEffects(deltaTime);
        HighlightCenterObject();
        UpdateDynamicMusic(deltaTime);
      // DEUS_EX AMSD For multiplayer...
      MultiplayerTick(deltaTime);
        FrobTime += deltaTime;

        if (bOnFire)
            ExtinguishFire();

        // save some texture info
        FloorMaterial = GetFloorMaterial();
        WallMaterial = GetWallMaterial(WallNormal);

        // don't let the player run if swimming
        bIsWalking = True;

        // update our swimming info
        swimTimer -= deltaTime;
        swimTimer = FMax(0, swimTimer);

        if ( Role == ROLE_Authority )
        {
            if (swimTimer > 0)
                PainTime = swimTimer;
        }

        // Check if player has walked outside a first-person convo.
        CheckActiveConversationRadius();

        // Check if all the people involved in a conversation are 
        // still within a reasonable radius.
        CheckActorDistances();

        // Randomly spawn an air bubble every 0.2 seconds
        // Place them in front of the player's eyes
        swimBubbleTimer += deltaTime;
        if (swimBubbleTimer >= 0.2)
        {
            swimBubbleTimer = 0;
            if (FRand() < 0.4)
            {
                loc = Location + VRand() * 4;
                loc += Vector(ViewRotation) * CollisionRadius * 2;
                loc.Z += CollisionHeight * 0.9;
                Spawn(class'AirBubble', Self,, loc);
            }
        }

        // handle poison
      //DEUS_EX AMSD Now handled in multiplayertick
        //UpdatePoison(deltaTime);

        // Update Time Played
        UpdateTimePlayed(deltaTime);

        Super.PlayerTick(deltaTime);
    }

    function BeginState()
    {
        local float mult, augLevel;

        // set us to be two feet high
        SetBasedPawnSize(Default.CollisionRadius, 16);

        // get our skill info
        mult = SkillSystem.GetSkillLevelValue(class'SkillSwimming');
        swimDuration = UnderWaterTime * mult;
        swimTimer = swimDuration;
        swimBubbleTimer = 0;
        if (( Level.NetMode != NM_Standalone ) && Self.IsA('Human') )
        {
            if ( AugmentationSystem != None )
                augLevel = AugmentationSystem.GetAugLevelValue(class'AugAqualung');
            if ( augLevel == -1.0 )
                WaterSpeed = Human(Self).Default.mpWaterSpeed * mult;
            else
                WaterSpeed = Human(Self).Default.mpWaterSpeed * 2.0 * mult;
        }
        else
            WaterSpeed = Default.WaterSpeed * mult;

        Super.BeginState();
    }
}


// ----------------------------------------------------------------------
// state Dying
//
// make sure the death animation finishes
// ----------------------------------------------------------------------

state Dying
{
    ignores all;

    event PlayerTick(float deltaTime)
    {
      if (PlayerIsClient())      
         ClientDeath();
        UpdateDynamicMusic(deltaTime);

        Super.PlayerTick(deltaTime);
    }

    exec function Fire(optional float F)
    {
        if ( Level.NetMode != NM_Standalone )
        Super.Fire();
    }

    exec function ShowMainMenu()
    {
        // reduce the white glow when the menu is up
        if (InstantFog != vect(0,0,0))
        {
            InstantFog   = vect(0.1,0.1,0.1);
            InstantFlash = 0.01;

            // force an update
            ViewFlash(1.0);
        }

        Global.ShowMainMenu();
    }

    function BeginState()
    {
        FrobTime = Level.TimeSeconds;
        ShowHud(False);
      ClientDeath();
    }

   function TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
    {
    }

    function PlayerCalcView(out actor ViewActor, out vector CameraLocation, out rotator CameraRotation)
    {
        local vector ViewVect, HitLocation, HitNormal, whiteVec;
        local float ViewDist;
        local actor HitActor;
        local float time;

        ViewActor = Self;
        if (bHidden)
        {
            // spiral up and around carcass and fade to white in five seconds
            time = Level.TimeSeconds - FrobTime;

            if ( ((myKiller != None) && (killProfile != None) && (!killProfile.bKilledSelf)) || 
                  ((killProfile != None) && killProfile.bValid && (!killProfile.bKilledSelf)))
            {
                if ( killProfile.bValid && killProfile.bTurretKilled )
                    ViewVect = killProfile.killerLoc - Location;
                else if ( killProfile.bValid && killProfile.bProximityKilled )
                    ViewVect = killProfile.killerLoc - Location;
                else if (( !killProfile.bKilledSelf ) && ( myKiller != None ))
                    ViewVect = myKiller.Location - Location;
                CameraLocation = Location;
                CameraRotation = Rotator(ViewVect);
            }
            else if (time < 8.0)
            {
                whiteVec.X = time / 16.0;
                whiteVec.Y = time / 16.0;
                whiteVec.Z = time / 16.0;
                CameraRotation.Pitch = -16384;
                CameraRotation.Yaw = (time * 8192.0) % 65536;
                ViewDist = 32 + time * 32;
                InstantFog = whiteVec;
                InstantFlash = 0.5;
                ViewFlash(1.0);
                // make sure we don't go through the ceiling
                ViewVect = vect(0,0,1);
                HitActor = Trace(HitLocation, HitNormal, Location + ViewDist * ViewVect, Location);
                if ( HitActor != None )
                    CameraLocation = HitLocation;
                else
                    CameraLocation = Location + ViewDist * ViewVect;
            }
            else
            {
                if  ( Level.NetMode != NM_Standalone )
                {
                    // Don't fade to black in multiplayer
                }
                else
                {
                    // then, fade out to black in four seconds and bring up
                    // the main menu automatically
                    whiteVec.X = FMax(0.5 - (time-8.0) / 8.0, -1.0);
                    whiteVec.Y = FMax(0.5 - (time-8.0) / 8.0, -1.0);
                    whiteVec.Z = FMax(0.5 - (time-8.0) / 8.0, -1.0);
                    CameraRotation.Pitch = -16384;
                    CameraRotation.Yaw = (time * 8192.0) % 65536;
                     ViewDist = 32 + 8.0 * 32;
                    InstantFog = whiteVec;
                    InstantFlash = whiteVec.X;
                    ViewFlash(1.0);

                    // start the splash screen after a bit
                    // only if we don't have a menu open
                    // DEUS_EX AMSD Don't do this in multiplayer!!!!
                    if (Level.NetMode == NM_Standalone)
                    {
                        if (whiteVec == vect(-1.0,-1.0,-1.0))
                            if ((MenuUIWindow(DeusExRootWindow(rootWindow).GetTopWindow()) == None) &&
                                (ToolWindow(DeusExRootWindow(rootWindow).GetTopWindow()) == None))
                                ConsoleCommand("OPEN DXONLY");
                    }
                }
                // make sure we don't go through the ceiling
                ViewVect = vect(0,0,1);
                HitActor = Trace(HitLocation, HitNormal, Location + ViewDist * ViewVect, Location);
                if ( HitActor != None )
                    CameraLocation = HitLocation;
                else
                    CameraLocation = Location + ViewDist * ViewVect;
            }
        }
        else
        {
            // use FrobTime as the cool DeathCam timer
            FrobTime = Level.TimeSeconds;

            // make sure we don't go through the wall
            ViewDist = 190;
            ViewVect = vect(1,0,0) >> Rotation;
            HitActor = Trace( HitLocation, HitNormal, 
                    Location - ViewDist * vector(CameraRotation), Location, false, vect(12,12,2));
            if ( HitActor != None )
                CameraLocation = HitLocation;
            else
                CameraLocation = Location - ViewDist * ViewVect;
        }

        // don't fog view if we are "paused"
        if (DeusExRootWindow(rootWindow).bUIPaused)
        {
            InstantFog   = vect(0,0,0);
            InstantFlash = 0;
            ViewFlash(1.0);
        }
    }

Begin:
    // Dead players comes back to life with scope view, so this is here to prevent that
    if ( DeusExWeapon(inHand) != None )
    {
        DeusExWeapon(inHand).bZoomed = False;
        DeusExWeapon(inHand).RefreshScopeDisplay(Self, True, False);
    }

    if ( DeusExRootWindow(rootWindow).hud.augDisplay != None )
    {
        DeusExRootWindow(rootWindow).hud.augDisplay.bVisionActive = False;
        DeusExRootWindow(rootWindow).hud.augDisplay.activeCount = 0;
    }

    // Don't come back to life drugged or posioned
    poisonCounter       = 0; 
    poisonTimer         = 0;    
    drugEffectTimer = 0;

    // Don't come back to life crouched
    bCrouchOn           = False;
    bWasCrouchOn        = False;
    bIsCrouching        = False;
    bForceDuck          = False;
    lastbDuck           = 0;
    bDuck                   = 0;

    FrobTime = Level.TimeSeconds;
    bBehindView = True;
    Velocity = vect(0,0,0);
    Acceleration = vect(0,0,0);
    DesiredFOV = Default.DesiredFOV;
    FinishAnim();
    KillShadow();

   FlashTimer = 0;

    // hide us and spawn the carcass
    bHidden = True;
    SpawnCarcass();
   //DEUS_EX AMSD Players should not leave physical versions of themselves around :)
   if (Level.NetMode != NM_Standalone)
      HidePlayer();
}

// ----------------------------------------------------------------------
// state Interpolating
// ----------------------------------------------------------------------

state Interpolating
{
    ignores all;

    function TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
    {
    }

    // check to see if we are done interpolating, if so, then travel to the next map
    event InterpolateEnd(Actor Other)
    {
        if (InterpolationPoint(Other).bEndOfPath)
            if (NextMap != "")
            {
                // DEUS_EX_DEMO
                //
                // If this is the demo, show the demo splash screen, which
                // will exit the game after the player presses a key/mouseclick
//				if (NextMap == "02_NYC_BatteryPark")
//					ShowDemoSplash();
//				else
                    Level.Game.SendPlayer(Self, NextMap);
            }
    }

    exec function Fire(optional float F)
    {
        local DeusExLevelInfo info;

        // only bring up the menu if we're not in a mission outro
        info = GetLevelInfo();
        if ((info != None) && (info.MissionNumber < 0))
            ShowMainMenu();
    }

    event PlayerTick(float deltaTime)
    {
        UpdateInHand();
        UpdateDynamicMusic(deltaTime);
        ShowHud(False);
    }

Begin:
    if (bOnFire)
        ExtinguishFire();

    bDetectable = False;

    // put away your weapon
    if (Weapon != None)
    {
        Weapon.bHideWeapon = True;
        Weapon = None;
        PutInHand(None);
    }

    // can't carry decorations across levels
    if (CarriedDecoration != None)
    {
        CarriedDecoration.Destroy();
        CarriedDecoration = None;
    }

    PlayAnim('Still');
}

// ----------------------------------------------------------------------
// state Paralyzed
// ----------------------------------------------------------------------

state Paralyzed
{
    ignores all;

    function TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
    {
    }

    exec function Fire(optional float F)
    {
        ShowMainMenu();
    }

    event PlayerTick(float deltaTime)
    {
        UpdateInHand();
        ShowHud(False);
        ViewFlash(deltaTime);
    }

Begin:
    if (bOnFire)
        ExtinguishFire();

    bDetectable = False;

    // put away your weapon
    if (Weapon != None)
    {
        Weapon.bHideWeapon = True;
        Weapon = None;
        PutInHand(None);
    }

    // can't carry decorations across levels
    if (CarriedDecoration != None)
    {
        CarriedDecoration.Destroy();
        CarriedDecoration = None;
    }

    SetPhysics(PHYS_None);
    PlayAnim('Still');
    Stop;

Letterbox:
    if (bOnFire)
        ExtinguishFire();

    bDetectable = False;

    // put away your weapon
    if (Weapon != None)
    {
        Weapon.bHideWeapon = True;
        Weapon = None;
        PutInHand(None);
    }

    // can't carry decorations across levels
    if (CarriedDecoration != None)
    {
        CarriedDecoration.Destroy();
        CarriedDecoration = None;
    }

    SetPhysics(PHYS_None);
    PlayAnim('Still');
    if (rootWindow != None)
        rootWindow.NewChild(class'CinematicWindow');
}

// ----------------------------------------------------------------------
// RenderOverlays()
// render our in-hand object
// ----------------------------------------------------------------------

simulated event RenderOverlays( canvas Canvas )
{
   Super.RenderOverlays(Canvas);

    if (!IsInState('Interpolating') && !IsInState('Paralyzed'))
        if ((inHand != None) && (!inHand.IsA('Weapon')))
            inHand.RenderOverlays(Canvas);
}

// ----------------------------------------------------------------------
// RestrictInput()
//
// Are we in a state which doesn't allow certain exec functions?
// ----------------------------------------------------------------------

function bool RestrictInput()
{
    if (IsInState('Interpolating') || IsInState('Dying') || IsInState('Paralyzed'))
        return True;

    return False;
}


// ----------------------------------------------------------------------
// DroneExplode
// ----------------------------------------------------------------------
function DroneExplode()
{
    local AugDrone anAug;

    if (aDrone != None)
    {
        aDrone.Explode(aDrone.Location, vect(0,0,1));
      //DEUS_EX AMSD Don't blow up OTHER player drones...
      anAug = AugDrone(AugmentationSystem.FindAugmentation(class'AugDrone'));
        //foreach AllActors(class'AugDrone', anAug)			
      if (anAug != None)      
         anAug.Deactivate();
    }
}

// ----------------------------------------------------------------------
// BuySkills()
// ----------------------------------------------------------------------

exec function BuySkills()
{
    if ( Level.NetMode != NM_Standalone )
    {
        // First turn off scores if we're heading into skill menu
        if ( !bBuySkills )
            ClientTurnOffScores();

        bBuySkills = !bBuySkills;
        BuySkillSound( 2 );
    }
}

// ----------------------------------------------------------------------
// KillerProfile()
// ----------------------------------------------------------------------

exec function KillerProfile()
{
    bKillerProfile = !bKillerProfile;
}

// ----------------------------------------------------------------------
// ClientTurnOffScores()
// ----------------------------------------------------------------------
function ClientTurnOffScores()
{
    if ( bShowScores )
        bShowScores = False;
}

// ----------------------------------------------------------------------
/// ShowScores()
// ----------------------------------------------------------------------

exec function ShowScores()
{
    if ( bBuySkills && !bShowScores )
        BuySkills();

    bShowScores = !bShowScores;
}

// ----------------------------------------------------------------------
// ParseLeftClick()
// ----------------------------------------------------------------------

exec function ParseLeftClick()
{
    //
    // ParseLeftClick deals with things in your HAND
    //
    // Precedence:
    // - Detonate spy drone
    // - Fire (handled automatically by user.ini bindings)
    // - Use inHand
    //

    if (RestrictInput())
        return;

    // if the spy drone augmentation is active, blow it up
    if (bSpyDroneActive)
    {
        DroneExplode();
        return;
    }

    if ((inHand != None) && !bInHandTransition)
    {
        if (inHand.bActivatable)
            inHand.Activate();
        else if (FrobTarget != None)
        {
            // special case for using keys or lockpicks on doors
            if (FrobTarget.IsA('DeusExMover'))
                if (inHand.IsA('NanoKeyRing') || inHand.IsA('Lockpick'))
                    DoFrob(Self, inHand);

            // special case for using multitools on hackable things
            if (FrobTarget.IsA('HackableDevices'))
            {
                if (inHand.IsA('Multitool'))
                {
                    if (( Level.Netmode != NM_Standalone ) && (TeamDMGame(DXGame) != None) && FrobTarget.IsA('AutoTurretGun') && (AutoTurretGun(FrobTarget).team==PlayerReplicationInfo.team) )
                    {
                        MultiplayerNotifyMsg( MPMSG_TeamHackTurret );
                        return;
                    }
                    else
                        DoFrob(Self, inHand);
                }
            }
        }
    }
}

// ----------------------------------------------------------------------
// ParseRightClick()
// ----------------------------------------------------------------------

exec function ParseRightClick()
{
    //
    // ParseRightClick deals with things in the WORLD
    //
    // Precedence:
    // - Pickup highlighted Inventory
    // - Frob highlighted object
    // - Grab highlighted Decoration
    // - Put away (or drop if it's a deco) inHand
    //

    local AutoTurret turret;
    local int ViewIndex;
    local bool bPlayerOwnsIt;
   local Inventory oldFirstItem;
    local Inventory oldInHand;
    local Decoration oldCarriedDecoration;
    local Vector loc;

    if (RestrictInput())
        return;

   oldFirstItem = Inventory;
    oldInHand = inHand;
    oldCarriedDecoration = CarriedDecoration;

    if (FrobTarget != None)
        loc = FrobTarget.Location;

    if (FrobTarget != None)
    {
        // First check if this is a NanoKey, in which case we just
        // want to add it to the NanoKeyRing without disrupting
        // what the player is holding

        if (FrobTarget.IsA('NanoKey'))
        {
            PickupNanoKey(NanoKey(FrobTarget));
            FrobTarget.Destroy();
            FrobTarget = None;
            return;
        }
        else if (FrobTarget.IsA('Inventory'))
        {
            // If this is an item that can be stacked, check to see if 
            // we already have one, in which case we don't need to 
            // allocate more space in the inventory grid.
            // 
            // TODO: This logic may have to get more involved if/when 
            // we start allowing other types of objects to get stacked.

            if (HandleItemPickup(FrobTarget, True) == False)
                return;

            // if the frob succeeded, put it in the player's inventory
         //DEUS_EX AMSD ARGH! Because of the way respawning works, the item I pick up
         //is NOT the same as the frobtarget if I do a pickup.  So how do I tell that
         //I've successfully picked it up?  Well, if the first item in my inventory 
         //changed, I picked up a new item.
            if ( ((Level.NetMode == NM_Standalone) && (Inventory(FrobTarget).Owner == Self)) ||
              ((Level.NetMode != NM_Standalone) && (oldFirstItem != Inventory)) )
            {
            if (Level.NetMode == NM_Standalone)
               FindInventorySlot(Inventory(FrobTarget));
            else
               FindInventorySlot(Inventory);
                FrobTarget = None;
            }
        }
        else if (FrobTarget.IsA('Decoration') && Decoration(FrobTarget).bPushable)
        {
            GrabDecoration();
        }
        else
        {
            if (( Level.NetMode != NM_Standalone ) && ( TeamDMGame(DXGame) != None ))
            {
                if ( FrobTarget.IsA('LAM') || FrobTarget.IsA('GasGrenade') || FrobTarget.IsA('EMPGrenade'))
                {
                    if ((ThrownProjectile(FrobTarget).team == PlayerReplicationInfo.team) && ( ThrownProjectile(FrobTarget).Owner != Self ))
                    {
                        if ( ThrownProjectile(FrobTarget).bDisabled )       // You can re-enable a grenade for a teammate
                        {
                            ThrownProjectile(FrobTarget).ReEnable();
                            return;
                        }
                        MultiplayerNotifyMsg( MPMSG_TeamLAM );
                        return;
                    }
                }
                if ( FrobTarget.IsA('ComputerSecurity') && (PlayerReplicationInfo.team == ComputerSecurity(FrobTarget).team) )
                {
                    // Let controlling player re-hack his/her own computer
                    bPlayerOwnsIt = False;
                    foreach AllActors(class'AutoTurret',turret)
                    {
                        for (ViewIndex = 0; ViewIndex < ArrayCount(ComputerSecurity(FrobTarget).Views); ViewIndex++)
                        {
                            if (ComputerSecurity(FrobTarget).Views[ViewIndex].turretTag == turret.Tag)
                            {
                                if (( turret.safeTarget == Self ) || ( turret.savedTarget == Self ))
                                {
                                    bPlayerOwnsIt = True;
                                    break;
                                }
                            }
                        }
                    }
                    if ( !bPlayerOwnsIt )
                    {
                        MultiplayerNotifyMsg( MPMSG_TeamComputer );
                        return;
                    }
                }
            }
            // otherwise, just frob it
            DoFrob(Self, None);
        }
    }
    else
    {
        // if there's no FrobTarget, put away an inventory item or drop a decoration
        // or drop the corpse
        if ((inHand != None) && inHand.IsA('POVCorpse'))
            DropItem();
        else
            PutInHand(None);
    }

    if ((oldInHand == None) && (inHand != None))
        PlayPickupAnim(loc);
    else if ((oldCarriedDecoration == None) && (CarriedDecoration != None))
        PlayPickupAnim(loc);
}

// ----------------------------------------------------------------------
// PlayPickupAnim()
// ----------------------------------------------------------------------

function PlayPickupAnim(Vector locPickup)
{
    if (Location.Z - locPickup.Z < 16)
        PlayAnim('PushButton',,0.1);
    else
        PlayAnim('Pickup',,0.1);
}

// ----------------------------------------------------------------------
// HandleItemPickup()
// ----------------------------------------------------------------------

function bool HandleItemPickup(Actor FrobTarget, optional bool bSearchOnly)
{
    local bool bCanPickup;
    local bool bSlotSearchNeeded;
    local Inventory foundItem;

    bSlotSearchNeeded = True;
    bCanPickup = True;

    // Special checks for objects that do not require phsyical inventory
    // in order to be picked up:
    // 
    // - NanoKeys
    // - DataVaultImages
    // - Credits

    if ((FrobTarget.IsA('DataVaultImage')) || (FrobTarget.IsA('NanoKey')) || (FrobTarget.IsA('Credits')))
    {
        bSlotSearchNeeded = False;
    }
    else if (FrobTarget.IsA('DeusExPickup'))
    {
        // If an object of this type already exists in the player's inventory *AND*
        // the object is stackable, then we don't need to search.

        if ((FindInventoryType(FrobTarget.Class) != None) && (DeusExPickup(FrobTarget).bCanHaveMultipleCopies))
            bSlotSearchNeeded = False;
    }
    else 
    {
        // If this isn't ammo or a weapon that we already have, 
        // check if there's enough room in the player's inventory
        // to hold this item.

        foundItem = GetWeaponOrAmmo(Inventory(FrobTarget));

        if (foundItem != None)
        {
            bSlotSearchNeeded = False;

            // if this is an ammo, and we're full of it, abort the pickup
            if (foundItem.IsA('Ammo'))
            {
                if (Ammo(foundItem).AmmoAmount >= Ammo(foundItem).MaxAmmo)
                {
                    ClientMessage(TooMuchAmmo);
                    bCanPickup = False;
                }
            }

            // If this is a grenade or LAM (what a pain in the ass) then also check
            // to make sure we don't have too many grenades already
            else if ((foundItem.IsA('WeaponEMPGrenade')) || 
                (foundItem.IsA('WeaponGasGrenade')) || 
                (foundItem.IsA('WeaponNanoVirusGrenade')) || 
                (foundItem.IsA('WeaponLAM')))
            {
                if (DeusExWeapon(foundItem).AmmoType.AmmoAmount >= DeusExWeapon(foundItem).AmmoType.MaxAmmo)
                {
                    ClientMessage(TooMuchAmmo);
                    bCanPickup = False;
                }
            }


            // Otherwise, if this is a single-use weapon, prevent the player
            // from picking up

            else if (foundItem.IsA('Weapon'))
            {
                // If these fields are set as checked, then this is a 
                // single use weapon, and if we already have one in our 
                // inventory another cannot be picked up (puke). 

                bCanPickup = ! ( (Weapon(foundItem).ReloadCount == 0) && 
                                 (Weapon(foundItem).PickupAmmoCount == 0) && 
                                 (Weapon(foundItem).AmmoName != None) );

                if (!bCanPickup)
                    ClientMessage(Sprintf(CanCarryOnlyOne, foundItem.itemName));

            }
        }
    }
    
    if (bSlotSearchNeeded && bCanPickup)
    {
        if (FindInventorySlot(Inventory(FrobTarget), bSearchOnly) == False)
        {
            ClientMessage(Sprintf(InventoryFull, Inventory(FrobTarget).itemName));
            bCanPickup = False;
            ServerConditionalNotifyMsg( MPMSG_DropItem );
        }
    }
    
    if (bCanPickup)
    {
        if ( (Level.NetMode != NM_Standalone) && (FrobTarget.IsA('DeusExWeapon') || FrobTarget.IsA('DeusExAmmo')) )
            PlaySound(sound'WeaponPickup', SLOT_Interact, 0.5+FRand()*0.25, , 256, 0.95+FRand()*0.1);
        DoFrob(Self, inHand);

        // This is bad. We need to reset the number so restocking works
        if ( Level.NetMode != NM_Standalone )
        {
            if ( FrobTarget.IsA('DeusExWeapon') && (DeusExWeapon(FrobTarget).PickupAmmoCount == 0) )
            {
                DeusExWeapon(FrobTarget).PickupAmmoCount = DeusExWeapon(FrobTarget).Default.mpPickupAmmoCount * 3;
            }
        }
    }

    return bCanPickup;
}

// ----------------------------------------------------------------------
// CreateNanoKeyInfo()
// ----------------------------------------------------------------------

function NanoKeyInfo CreateNanoKeyInfo()
{
    local NanoKeyInfo newKey;

    newKey = new(Self) Class'NanoKeyInfo';

    return newKey;
}

// ----------------------------------------------------------------------
// PickupNanoKey()
// 
// Picks up a NanoKey
//
// 1. Add KeyID to list of keys
// 2. Destroy NanoKey (since the user can't have it in his/her inventory)
// ----------------------------------------------------------------------

function PickupNanoKey(NanoKey newKey)
{
    KeyRing.GiveKey(newKey.KeyID, newKey.Description);
   //DEUS_EX AMSD In multiplayer, propagate the key to the client if the server
   if ((Role == ROLE_Authority) && (Level.NetMode != NM_Standalone))
   {
      KeyRing.GiveClientKey(newKey.KeyID, newKey.Description);
   }   
    ClientMessage(Sprintf(AddedNanoKey, newKey.Description));
}

// ----------------------------------------------------------------------
// RemoveNanoKey()
// ----------------------------------------------------------------------

exec function RemoveNanoKey(Name KeyToRemove)
{
    if (!bCheatsEnabled)
        return;

    KeyRing.RemoveKey(KeyToRemove);
   if ((Role == ROLE_Authority) && (Level.NetMode != NM_Standalone))
   {
      KeyRing.RemoveClientKey(KeyToRemove);
   }   
}

// ----------------------------------------------------------------------
// GiveNanoKey()
// ----------------------------------------------------------------------

exec function GiveNanoKey(Name newKeyID, String newDescription)
{
    if (!bCheatsEnabled)
        return;

    KeyRing.GiveKey(newKeyID, newDescription);
   //DEUS_EX AMSD In multiplayer, propagate the key to the client if the server
   if ((Role == ROLE_Authority) && (Level.NetMode != NM_Standalone))
   {
      KeyRing.GiveClientKey(newKeyID, newDescription);
   }

}

// ----------------------------------------------------------------------
// DoFrob()
// 
// Frob the target
// ----------------------------------------------------------------------

function DoFrob(Actor Frobber, Inventory frobWith)
{
    local DeusExRootWindow root;
    local Ammo ammo;
    local Inventory item;
    local Actor A;

    // make sure nothing is based on us if we're an inventory
    if (FrobTarget.IsA('Inventory'))
        foreach FrobTarget.BasedActors(class'Actor', A)
            A.SetBase(None);

    FrobTarget.Frob(Frobber, frobWith);

    // if the object destroyed itself, get out
    if (FrobTarget == None)
        return;

    // if the inventory item aborted it's own pickup, get out
    if (FrobTarget.IsA('Inventory') && (FrobTarget.Owner != Self))
        return;

    // alert NPCs that I'm messing with stuff
    if (FrobTarget.bOwned)
        AISendEvent('Futz', EAITYPE_Visual);

    // play an animation
    PlayPickupAnim(FrobTarget.Location);

    // set the base so the inventory follows us around correctly
    if (FrobTarget.IsA('Inventory'))
        FrobTarget.SetBase(Frobber);
}

// ----------------------------------------------------------------------
// PutInHand()
//
// put the object in the player's hand and draw it in front of the player
// ----------------------------------------------------------------------

exec function PutInHand(optional Inventory inv)
{
    if (RestrictInput())
        return;

    // can't put anything in hand if you're using a spy drone
    if ((inHand == None) && bSpyDroneActive)
        return;

    // can't do anything if you're carrying a corpse
    if ((inHand != None) && inHand.IsA('POVCorpse'))
        return;

    if (inv != None)
    {
        // can't put ammo in hand
        if (inv.IsA('Ammo'))
            return;

        // Can't put an active charged item in hand
        if ((inv.IsA('ChargedPickup')) && (ChargedPickup(inv).IsActive()))
            return;
    }

    if (CarriedDecoration != None)
        DropDecoration();

    SetInHandPending(inv);
}

// ----------------------------------------------------------------------
// UpdateBeltText()
// ----------------------------------------------------------------------

function UpdateBeltText(Inventory item)
{
    local DeusExRootWindow root;

    root = DeusExRootWindow(rootWindow);

    // Update object belt text
    if ((item.bInObjectBelt) && (root != None))
        root.hud.belt.UpdateObjectText(item.beltPos);       
}

// ----------------------------------------------------------------------
// UpdateAmmoBeltText()
//
// Loops through all the weapons in the player's inventory and updates
// the ammo for any that matches the ammo type passed in.
// ----------------------------------------------------------------------

function UpdateAmmoBeltText(Ammo ammo)
{
    local Inventory inv;

    inv = Inventory;
    while(inv != None)
    {
        if ((inv.IsA('DeusExWeapon')) && (DeusExWeapon(inv).AmmoType == ammo))
            UpdateBeltText(inv);

        inv = inv.Inventory;
    }
}

// ----------------------------------------------------------------------
// SetInHand()
// ----------------------------------------------------------------------

function SetInHand(Inventory newInHand)
{
    local DeusExRootWindow root;

    inHand = newInHand;

    // Notify the hud
    root = DeusExRootWindow(rootWindow);
    if (root != None)
        root.hud.belt.UpdateInHand();
}

// ----------------------------------------------------------------------
// SetInHandPending()
// ----------------------------------------------------------------------

function SetInHandPending(Inventory newInHandPending)
{
    local DeusExRootWindow root;

    if ( newInHandPending == None )
        ClientInHandPending = None;

    inHandPending = newInHandPending;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        root.hud.belt.UpdateInHand();
}

// ----------------------------------------------------------------------
// UpdateInHand()
//
// Called every frame
// Checks the state of inHandPending and deals with animation and crap
// 1. Check for pending item
// 2. Play down anim (and deactivate) for inHand and wait for it to finish
// 3. Assign inHandPending to inHand (and SelectedItem)
// 4. Play up anim for inHand
// ----------------------------------------------------------------------

function UpdateInHand()
{
    local bool bSwitch;

    //sync up clientinhandpending.
    if (inHandPending != inHand)
        ClientInHandPending = inHandPending;

   //DEUS_EX AMSD  Don't let clients do this.
   if (Role < ROLE_Authority)
      return;

    if (inHand != inHandPending)
    {
        bInHandTransition = True;
        bSwitch = False;
        if (inHand != None)
        {
            // turn it off if it is on
            if (inHand.bActive)
                inHand.Activate();

            if (inHand.IsA('SkilledTool'))
            {
                if (inHand.IsInState('Idle'))
            {
                    SkilledTool(inHand).PutDown();
            }
                else if (inHand.IsInState('Idle2'))
            {
                    bSwitch = True;
            }
            }
            else if (inHand.IsA('DeusExWeapon'))
            {
                if (inHand.IsInState('Idle') || inHand.IsInState('Reload'))
                    DeusExWeapon(inHand).PutDown();
                else if (inHand.IsInState('DownWeapon') && (Weapon == None))
                    bSwitch = True;
            }
            else
            {
                bSwitch = True;
            }
        }
        else
        {
            bSwitch = True;
        }

        // OK to actually switch?
        if (bSwitch)
        {
            SetInHand(inHandPending);
            SelectedItem = inHandPending;

            if (inHand != None)
            {
                if (inHand.IsA('SkilledTool'))
                    SkilledTool(inHand).BringUp();
                else if (inHand.IsA('DeusExWeapon'))
                    SwitchWeapon(DeusExWeapon(inHand).InventoryGroup);
            }
        }
    }
    else
    {
        bInHandTransition = False;

        // Added this code because it's now possible to reselect an in-hand
        // item while we're putting it down, so we need to bring it back up...

        if (inHand != None)
        {
            // if we put the item away, bring it back up
            if (inHand.IsA('SkilledTool'))
            {
                if (inHand.IsInState('Idle2'))
                    SkilledTool(inHand).BringUp();
            }
            else if (inHand.IsA('DeusExWeapon'))
            {
                if (inHand.IsInState('DownWeapon') && (Weapon == None))
                    SwitchWeapon(DeusExWeapon(inHand).InventoryGroup);
            }
        }

    }

    UpdateCarcassEvent();
}

// ----------------------------------------------------------------------
// UpdateCarcassEvent()
// 
// Small hack for sending carcass events
// ----------------------------------------------------------------------

function UpdateCarcassEvent()
{
    if ((inHand != None) && (inHand.IsA('POVCorpse')))
        AIStartEvent('Carcass', EAITYPE_Visual);
    else
        AIEndEvent('Carcass', EAITYPE_Visual);
}

// ----------------------------------------------------------------------
// IsEmptyItemSlot()
//
// Returns True if the item will fit in this slot
// ----------------------------------------------------------------------

function Bool IsEmptyItemSlot( Inventory anItem, int col, int row )
{
    local int slotsCol;
    local int slotsRow;
    local Bool bEmpty;

    if ( anItem == None )
        return False;

    // First make sure the item can fit horizontally
    // and vertically
    if (( col + anItem.invSlotsX > maxInvCols ) ||
        ( row + anItem.invSlotsY > maxInvRows ))
            return False;

   if ((Level.NetMode != NM_Standalone) && (bBeltIsMPInventory))
      return True;

    // Now check this and the needed surrounding slots
    // to see if all the slots are empty

    bEmpty = True;
    for( slotsRow=0; slotsRow < anItem.invSlotsY; slotsRow++ )
    {
        for ( slotsCol=0; slotsCol < anItem.invSlotsX; slotsCol++ )
        {
            if ( invSlots[((slotsRow + row) * maxInvCols) + (slotsCol + col)] == 1 )
            {
                bEmpty = False;
                break;
            }
        }

        if ( !bEmpty )
            break;
    }

    return bEmpty;
}

// ----------------------------------------------------------------------
// IsEmptyItemSlotXY()
//
// Returns True if the item will fit in this slot
// ----------------------------------------------------------------------

function Bool IsEmptyItemSlotXY( int invSlotsX, int invSlotsY, int col, int row )
{
    local int slotsCol;
    local int slotsRow;
    local Bool bEmpty;

    // First make sure the item can fit horizontally
    // and vertically
    if (( col + invSlotsX > maxInvCols ) ||
        ( row + invSlotsY > maxInvRows ))
            return False;

   if ((Level.NetMode != NM_Standalone) && (bBeltIsMPInventory))
      return True;

   // Now check this and the needed surrounding slots
    // to see if all the slots are empty

    bEmpty = True;
    for( slotsRow=0; slotsRow < invSlotsY; slotsRow++ )
    {
        for ( slotsCol=0; slotsCol < invSlotsX; slotsCol++ )
        {
            if ( invSlots[((slotsRow + row) * maxInvCols) + (slotsCol + col)] == 1 )
            {
                bEmpty = False;
                break;
            }
        }

        if ( !bEmpty )
            break;
    }

    return bEmpty;
}

// ----------------------------------------------------------------------
// SetInvSlots()
// ----------------------------------------------------------------------

function SetInvSlots( Inventory anItem, int newValue )
{
    local int slotsCol;
    local int slotsRow;

    if ( anItem == None )
        return;

    // Make sure this item is located in a valid position
    if (( anItem.invPosX != -1 ) && ( anItem.invPosY != -1 ))
    {
        // fill inventory slots
        for( slotsRow=0; slotsRow < anItem.invSlotsY; slotsRow++ )
            for ( slotsCol=0; slotsCol < anItem.invSlotsX; slotsCol++ )
                invSlots[((slotsRow + anItem.invPosY) * maxInvCols) + (slotsCol + anItem.invPosX)] = newValue;
    }
}

// ----------------------------------------------------------------------
// PlaceItemInSlot()
// ----------------------------------------------------------------------

function PlaceItemInSlot( Inventory anItem, int col, int row )
{
    // Save in the original Inventory item also
    anItem.invPosX = col;
    anItem.invPosY = row;

    SetInvSlots(anItem, 1);
}

// ----------------------------------------------------------------------
// RemoveItemFromSlot()
//
// Removes an inventory item from the inventory grid
// ----------------------------------------------------------------------

function RemoveItemFromSlot(Inventory anItem)
{
    if (anItem != None)
    {
        SetInvSlots(anItem, 0);
        anItem.invPosX = -1;
        anItem.invPosY = -1;
    }
}

// ----------------------------------------------------------------------
// ClearInventorySlots()
//
// Not for the foolhardy
// ----------------------------------------------------------------------

function ClearInventorySlots()
{
    local int slotIndex;

    for(slotIndex=0; slotIndex<arrayCount(invSlots); slotIndex++)
        invSlots[slotIndex] = 0;
}

// ----------------------------------------------------------------------
// FindInventorySlot()
//
// Searches through the inventory slot grid and attempts to find a 
// valid location for the item passed in.  Returns True if the item
// is placed, otherwise returns False.
// ----------------------------------------------------------------------

function Bool FindInventorySlot(Inventory anItem, optional Bool bSearchOnly)
{
    local bool bPositionFound;
    local int row;
    local int col;
    local int newSlotX;
    local int newSlotY;
   local int beltpos;
    local ammo foundAmmo;

    if (anItem == None)
        return False;
    
    // Special checks for objects that do not require phsyical inventory
    // in order to be picked up:
    // 
    // - NanoKeys
    // - DataVaultImages
    // - Credits
    // - Ammo

    if ((anItem.IsA('DataVaultImage')) || (anItem.IsA('NanoKey')) || (anItem.IsA('Credits')) || (anItem.IsA('Ammo')))
        return True;

   bPositionFound = False;
   // DEUS_EX AMSD In multiplayer, due to propagation delays, the inventory refreshers in the
   // personascreeninventory can keep bouncing items back and forth.  So just return true and
   // place the item where it already was.
   if ((anItem.invPosX != -1) && (anItem.invPosY != -1) && (Level.NetMode != NM_Standalone) && (!bSearchOnly))
   {
      SetInvSlots(anItem,1);
      log("Trying to place item "$anItem$" when already placed at "$anItem.invPosX$", "$anItem.invPosY$".");
      return True;
   }

    // Loop through all slots, looking for a fit
    for (row=0; row<maxInvRows; row++)
    {   
        if (row + anItem.invSlotsY > maxInvRows)
            break;

        // Make sure the item can fit vertically
        for(col=0; col<maxInvCols; col++)
        {
            if (IsEmptyItemSlot(anItem, col, row ))
            {
                bPositionFound = True;
                break;
            }
        }

        if (bPositionFound)
            break;
    }

   if ((Level.NetMode != NM_Standalone) && (bBeltIsMPInventory))
   {
      bPositionFound = False;
      beltpos = 0;
      if (DeusExRootWindow(rootWindow) != None)
      {
         for (beltpos = 0; beltpos < ArrayCount(DeusExRootWindow(rootWindow).hud.belt.objects); beltpos++)
         {
            if ( (DeusExRootWindow(rootWindow).hud.belt.objects[beltpos].item == None) && (anItem.TestMPBeltSpot(beltpos)) )
            {
               bPositionFound = True;
            }
         }
      }
      else
      {
         log("no belt to check");
      }
   }

   if ((bPositionFound) && (!bSearchOnly))
   {
        PlaceItemInSlot(anItem, col, row);
   }
   
    return bPositionFound;
}
                
// ----------------------------------------------------------------------
// FindInventorySlotXY()
//
// Searches for an available slot given the number of horizontal and
// vertical slots this item takes up.
// ----------------------------------------------------------------------

function Bool FindInventorySlotXY(int invSlotsX, int invSlotsY, out int newSlotX, out int newSlotY)
{
    local bool bPositionFound;
    local int row;
    local int col;

    bPositionFound = False;

    // Loop through all slots, looking for a fit
    for (row=0; row<maxInvRows; row++)
    {   
        if (row + invSlotsY > maxInvRows)
            break;

        // Make sure the item can fit vertically
        for(col=0; col<maxInvCols; col++)
        {
            if (IsEmptyItemSlotXY(invSlotsX, invSlotsY, col, row))
            {
                newSlotX = col;
                newSlotY = row;

                bPositionFound = True;
                break;
            }
        }

        if (bPositionFound)
            break;
    }

    return bPositionFound;
}

// ----------------------------------------------------------------------
// DumpInventoryGrid()
//
// Dumps the inventory grid to the log file.  Useful for debugging only.
// ----------------------------------------------------------------------

exec function DumpInventoryGrid()
{
    local int slotsCol;
    local int slotsRow;
    local String gridRow;

    log("DumpInventoryGrid()");
    log("=============================================================");
    
    log("        1 2 3 4 5");
    log("-----------------");


    for( slotsRow=0; slotsRow < maxInvRows; slotsRow++ )
    {
        gridRow = "Row #" $ slotsRow $ ": ";

        for ( slotsCol=0; slotsCol < maxInvCols; slotsCol++ )
        {
            if ( invSlots[(slotsRow * maxInvCols) + slotsCol] == 1)
                gridRow = gridRow $ "X ";
            else
                gridRow = gridRow $ "  ";
        }
        
        log(gridRow);
    }
    log("=============================================================");
}

// ----------------------------------------------------------------------
// Belt functions following are just callbacks to handle multiplayer 
// belt updating.  First arg is true if it's the invbelt, false if it's
// the hudbelt.
// ----------------------------------------------------------------------

function ClearPosition(int pos)
{
   if (DeusExRootWindow(rootWindow) != None)
      DeusExRootWindow(rootWindow).hud.belt.ClearPosition(pos);
}

function ClearBelt()
{
   if (DeusExRootWindow(rootWindow) != None)
      DeusExRootWindow(rootWindow).hud.belt.ClearBelt();
}

function RemoveObjectFromBelt(Inventory item)
{
   if (DeusExRootWindow(rootWindow) != None)
      DeusExRootWindow(rootWindow).hud.belt.RemoveObjectFromBelt(item);
}

function AddObjectToBelt(Inventory item, int pos, bool bOverride)
{
   if (DeusExRootWindow(rootWindow) != None)
      DeusExRootWindow(rootWindow).hud.belt.AddObjectToBelt(item,pos,bOverride);
}


// ----------------------------------------------------------------------
// GetWeaponOrAmmo()
//
// Checks to see if the player already has this weapon or ammo
// in his inventory.  Returns the item if found, or None if not.
// ----------------------------------------------------------------------

function Inventory GetWeaponOrAmmo(Inventory queryItem)
{
    // First check to see if this item is actually a weapon or ammo
    if ((Weapon(queryItem) != None) || (Ammo(queryItem) != None))
        return FindInventoryType(queryItem.Class);
    else 
        return None;
}

// ----------------------------------------------------------------------
// Summon()
//
// automatically prepend DeusEx. to the summoned class
// ----------------------------------------------------------------------

exec function Summon(string ClassName)
{
    if (!bCheatsEnabled)
        return;

    if(!bAdmin && (Level.Netmode != NM_Standalone))
        return;
    if(instr(ClassName, ".") == -1)
        ClassName = "DeusEx." $ ClassName;
    Super.Summon(ClassName);
}


// ----------------------------------------------------------------------
// SpawnMass()
//
// Spawns a bunch of actors around the player
// ----------------------------------------------------------------------

exec function SpawnMass(Name ClassName, optional int TotalCount)
{
    local actor        spawnee;
    local vector       spawnPos;
    local vector       center;
    local rotator      direction;
    local int          maxTries;
    local int          count;
    local int          numTries;
    local float        maxRange;
    local float        range;
    local float        angle;
    local class<Actor> spawnClass;
    local string        holdName;

    if (!bCheatsEnabled)
        return;

    if (!bAdmin && (Level.Netmode != NM_Standalone))
        return;

    if (instr(ClassName, ".") == -1)
        holdName = "DeusEx." $ ClassName;
    else
        holdName = "" $ ClassName;  // barf

    spawnClass = class<actor>(DynamicLoadObject(holdName, class'Class'));
    if (spawnClass == None)
    {
        ClientMessage("Illegal actor name "$GetItemName(String(ClassName)));
        return;
    }

    if (totalCount <= 0)
        totalCount = 10;
    if (totalCount > 250)
        totalCount = 250;
    maxTries = totalCount*2;
    count = 0;
    numTries = 0;
    maxRange = sqrt(totalCount/3.1416)*4*SpawnClass.Default.CollisionRadius;

    direction = ViewRotation;
    direction.pitch = 0;
    direction.roll  = 0;
    center = Location + Vector(direction)*(maxRange+SpawnClass.Default.CollisionRadius+CollisionRadius+20);
    while ((count < totalCount) && (numTries < maxTries))
    {
        angle = FRand()*3.14159265359*2;
        range = sqrt(FRand())*maxRange;
        spawnPos.X = sin(angle)*range;
        spawnPos.Y = cos(angle)*range;
        spawnPos.Z = 0;
        spawnee = spawn(SpawnClass,,,center+spawnPos, Rotation);
        if (spawnee != None)
            count++;
        numTries++;
    }

    ClientMessage(count$" actor(s) spawned");

}

// ----------------------------------------------------------------------
// ToggleWalk()
// ----------------------------------------------------------------------

exec function ToggleWalk()
{
    if (RestrictInput())
        return;

    bToggleWalk = !bToggleWalk;
}

// ----------------------------------------------------------------------
// ReloadWeapon()
//
// reloads the currently selected weapon
// ----------------------------------------------------------------------

exec function ReloadWeapon()
{
    local DeusExWeapon W;

    if (RestrictInput())
        return;

    W = DeusExWeapon(Weapon);
    if (W != None)
        W.ReloadAmmo();
}

// ----------------------------------------------------------------------
// ToggleScope()
//
// turns the scope on or off for the current weapon
// ----------------------------------------------------------------------

exec function ToggleScope()
{
    local DeusExWeapon W;

    if (RestrictInput())
        return;

    W = DeusExWeapon(Weapon);
    if (W != None)
        W.ScopeToggle();
}

// ----------------------------------------------------------------------
// ToggleLaser()
//
// turns the laser sight on or off for the current weapon
// ----------------------------------------------------------------------

exec function ToggleLaser()
{
    local DeusExWeapon W;

    if (RestrictInput())
        return;

    W = DeusExWeapon(Weapon);
    if (W != None)
        W.LaserToggle();
}

// check to see if the player can lift a certain decoration taking
// into account his muscle augs
function bool CanBeLifted(Decoration deco)
{
    local int augLevel, augMult;
    local float maxLift;

    maxLift = 50;
    if (AugmentationSystem != None)
    {
        augLevel = AugmentationSystem.GetClassLevel(class'AugMuscle');
        augMult = 1;
        if (augLevel >= 0)
            augMult = augLevel+2;
        maxLift *= augMult;
    }

    if (!deco.bPushable || (deco.Mass > maxLift) || (deco.StandingCount > 0))
    {
        if (deco.bPushable)
            ClientMessage(TooHeavyToLift);
        else
            ClientMessage(CannotLift);

        return False;
    }

    return True;
}

// ----------------------------------------------------------------------
// GrabDecoration()
//
// This overrides GrabDecoration() in Pawn.uc
// lets the strength augmentation affect how much the player can lift
// ----------------------------------------------------------------------

function GrabDecoration()
{
    // can't grab decorations while leaning
    if (IsLeaning())
        return;

    // can't grab decorations while holding something else
    if (inHand != None)
    {
        ClientMessage(HandsFull);
        return;
    }

    if (carriedDecoration == None)
        if ((FrobTarget != None) && FrobTarget.IsA('Decoration') && (Weapon == None))
            if (CanBeLifted(Decoration(FrobTarget)))
            {
                CarriedDecoration = Decoration(FrobTarget);
                PutCarriedDecorationInHand();
            }
}
    
// ----------------------------------------------------------------------
// PutCarriedDecorationInHand()
// ----------------------------------------------------------------------

function PutCarriedDecorationInHand()
{
    local vector lookDir, upDir;

    if (CarriedDecoration != None)
    {
        lookDir = Vector(Rotation);
        lookDir.Z = 0;              
        upDir = vect(0,0,0);
        upDir.Z = CollisionHeight / 2;      // put it up near eye level
        CarriedDecoration.SetPhysics(PHYS_Falling);

        if ( CarriedDecoration.SetLocation(Location + upDir + (0.5 * CollisionRadius + CarriedDecoration.CollisionRadius) * lookDir) )
        {
            CarriedDecoration.SetPhysics(PHYS_None);
            CarriedDecoration.SetBase(self);
            CarriedDecoration.SetCollision(False, False, False);
            CarriedDecoration.bCollideWorld = False;

            // make it translucent
            CarriedDecoration.Style = STY_Translucent;
            CarriedDecoration.ScaleGlow = 1.0;
            CarriedDecoration.bUnlit = True;

            FrobTarget = None;
        }
        else
        {
            ClientMessage(NoRoomToLift);
            CarriedDecoration = None;
        }
    }
}

// ----------------------------------------------------------------------
// DropDecoration()
//
// This overrides DropDecoration() in Pawn.uc
// lets the player throw a decoration instead of just dropping it
// ----------------------------------------------------------------------

function DropDecoration()
{
    local Vector X, Y, Z, dropVect, origLoc, HitLocation, HitNormal, extent;
    local float velscale, size, mult;
    local bool bSuccess;
    local Actor hitActor;

    bSuccess = False;

    if (CarriedDecoration != None)
    {
        origLoc = CarriedDecoration.Location;
        GetAxes(Rotation, X, Y, Z);

        // if we are highlighting something, try to place the object on the target
        if ((FrobTarget != None) && !FrobTarget.IsA('Pawn'))
        {
            CarriedDecoration.Velocity = vect(0,0,0);

            // try to drop the object about one foot above the target
            size = FrobTarget.CollisionRadius - CarriedDecoration.CollisionRadius * 2;
            dropVect.X = size/2 - FRand() * size;
            dropVect.Y = size/2 - FRand() * size;
            dropVect.Z = FrobTarget.CollisionHeight + CarriedDecoration.CollisionHeight + 16;
            dropVect += FrobTarget.Location;
        }
        else
        {
            // throw velocity is based on augmentation
            if (AugmentationSystem != None)
            {
                mult = AugmentationSystem.GetAugLevelValue(class'AugMuscle');
                if (mult == -1.0)
                    mult = 1.0;
            }

            if (IsLeaning())
                CarriedDecoration.Velocity = vect(0,0,0);
            else
                CarriedDecoration.Velocity = Vector(ViewRotation) * mult * 500 + vect(0,0,220) + 40 * VRand();

            // scale it based on the mass
            velscale = FClamp(CarriedDecoration.Mass / 20.0, 1.0, 40.0);

            CarriedDecoration.Velocity /= velscale;
            dropVect = Location + (CarriedDecoration.CollisionRadius + CollisionRadius + 4) * X;
            dropVect.Z += BaseEyeHeight;
        }

        // is anything blocking the drop point? (like thin doors)
        if (FastTrace(dropVect))
        {
            CarriedDecoration.SetCollision(True, True, True);
            CarriedDecoration.bCollideWorld = True;

            // check to see if there's space there
            extent.X = CarriedDecoration.CollisionRadius;
            extent.Y = CarriedDecoration.CollisionRadius;
            extent.Z = 1;
            hitActor = Trace(HitLocation, HitNormal, dropVect, CarriedDecoration.Location, True, extent);

            if ((hitActor == None) && CarriedDecoration.SetLocation(dropVect))
                bSuccess = True;
            else
            {
                CarriedDecoration.SetCollision(False, False, False);
                CarriedDecoration.bCollideWorld = False;
            }
        }

        // if we can drop it here, then drop it
        if (bSuccess)
        {
            CarriedDecoration.bWasCarried = True;
            CarriedDecoration.SetBase(None);
            CarriedDecoration.SetPhysics(PHYS_Falling);
            CarriedDecoration.Instigator = Self;

            // turn off translucency
            CarriedDecoration.Style = CarriedDecoration.Default.Style;
            CarriedDecoration.bUnlit = CarriedDecoration.Default.bUnlit;
            if (CarriedDecoration.IsA('DeusExDecoration'))
                DeusExDecoration(CarriedDecoration).ResetScaleGlow();

            CarriedDecoration = None;
        }
        else
        {
            // otherwise, don't drop it and display a message
            CarriedDecoration.SetLocation(origLoc);
            ClientMessage(CannotDropHere);
        }
    }
}

// ----------------------------------------------------------------------
// DropItem()
//
// throws an item where you are currently looking
// or places it on your currently highlighted object
// if None is passed in, it drops what's inHand
// ----------------------------------------------------------------------

exec function bool DropItem(optional Inventory inv, optional bool bDrop)
{
    local Inventory item;
    local Inventory previousItemInHand;
    local Vector X, Y, Z, dropVect;
    local float size, mult;
    local DeusExCarcass carc;
    local class<DeusExCarcass> carcClass;
    local bool bDropped;
    local bool bRemovedFromSlots;
    local int  itemPosX, itemPosY;

    bDropped = True;

    if (RestrictInput())
        return False;

    if (inv == None)
    {
        previousItemInHand = inHand;
        item = inHand;
    }
    else
    {
        item = inv;
    }

    if (item != None)
    {
        GetAxes(Rotation, X, Y, Z);
        dropVect = Location + (CollisionRadius + 2*item.CollisionRadius) * X;
        dropVect.Z += BaseEyeHeight;

        // check to see if we're blocked by terrain
        if (!FastTrace(dropVect))
        {
            ClientMessage(CannotDropHere);
            return False;
        }

        // don't drop it if it's in a strange state
        if (item.IsA('DeusExWeapon'))
        {
            if (!DeusExWeapon(item).IsInState('Idle') && !DeusExWeapon(item).IsInState('Idle2') &&
                !DeusExWeapon(item).IsInState('DownWeapon') && !DeusExWeapon(item).IsInState('Reload'))
            {
                return False;
            }
            else        // make sure the scope/laser are turned off
            {
                DeusExWeapon(item).ScopeOff();
                DeusExWeapon(item).LaserOff();
            }
        }

        // Don't allow active ChargedPickups to be dropped
        if ((item.IsA('ChargedPickup')) && (ChargedPickup(item).IsActive()))
        {
            return False;
        }

        // don't let us throw away the nanokeyring
        if (item.IsA('NanoKeyRing'))
        {
            return False;
        }

        // take it out of our hand
        if (item == inHand)
            PutInHand(None);

        // handle throwing pickups that stack
        if (item.IsA('DeusExPickup'))
        {
            // turn it off if it is on
            if (DeusExPickup(item).bActive)
                DeusExPickup(item).Activate();

            DeusExPickup(item).NumCopies--;
            UpdateBeltText(item);   

            if (DeusExPickup(item).NumCopies > 0)
            {
                // put it back in our hand, but only if it was in our
                // hand originally!!!
                if (previousItemInHand == item)
                    PutInHand(previousItemInHand);

                item = Spawn(item.Class, Owner);
            }
            else
            {
                // Keep track of this so we can undo it 
                // if necessary
                bRemovedFromSlots = True;
                itemPosX = item.invPosX;
                itemPosY = item.invPosY;

                // Remove it from the inventory slot grid
                RemoveItemFromSlot(item);

                // make sure we have one copy to throw!
                DeusExPickup(item).NumCopies = 1;
            }
        }
        else
        {
            // Keep track of this so we can undo it 
            // if necessary
            bRemovedFromSlots = True;
            itemPosX = item.invPosX;
            itemPosY = item.invPosY;

            // Remove it from the inventory slot grid
            RemoveItemFromSlot(item);
        }

        // if we are highlighting something, try to place the object on the target
        if ((FrobTarget != None) && !item.IsA('POVCorpse'))
        {
            item.Velocity = vect(0,0,0);

            // play the correct anim
            PlayPickupAnim(FrobTarget.Location);

            // try to drop the object about one foot above the target
            size = FrobTarget.CollisionRadius - item.CollisionRadius * 2;
            dropVect.X = size/2 - FRand() * size;
            dropVect.Y = size/2 - FRand() * size;
            dropVect.Z = FrobTarget.CollisionHeight + item.CollisionHeight + 16;
            if (FastTrace(dropVect))
            {
                item.DropFrom(FrobTarget.Location + dropVect);
            }
            else
            {
                ClientMessage(CannotDropHere);
                bDropped = False;
            }
        }
        else
        {
            // throw velocity is based on augmentation
            if (AugmentationSystem != None)
            {
                mult = AugmentationSystem.GetAugLevelValue(class'AugMuscle');
                if (mult == -1.0)
                    mult = 1.0;
            }

            if (bDrop)
            {
                item.Velocity = VRand() * 30;

                // play the correct anim
                PlayPickupAnim(item.Location);
            }
            else
            {
                item.Velocity = Vector(ViewRotation) * mult * 300 + vect(0,0,220) + 40 * VRand();

                // play a throw anim
                PlayAnim('Attack',,0.1);
            }

            GetAxes(ViewRotation, X, Y, Z);
            dropVect = Location + 0.8 * CollisionRadius * X;
            dropVect.Z += BaseEyeHeight;

            // if we are a corpse, spawn the actual carcass
            if (item.IsA('POVCorpse'))
            {
                if (POVCorpse(item).carcClassString != "")
                {
                    carcClass = class<DeusExCarcass>(DynamicLoadObject(POVCorpse(item).carcClassString, class'Class'));
                    if (carcClass != None)
                    {
                        carc = Spawn(carcClass);
                        if (carc != None)
                        {
                            carc.Mesh = carc.Mesh2;
                            carc.KillerAlliance = POVCorpse(item).KillerAlliance;
                            carc.KillerBindName = POVCorpse(item).KillerBindName;
                            carc.Alliance = POVCorpse(item).Alliance;
                            carc.bNotDead = POVCorpse(item).bNotDead;
                            carc.bEmitCarcass = POVCorpse(item).bEmitCarcass;
                            carc.CumulativeDamage = POVCorpse(item).CumulativeDamage;
                            carc.MaxDamage = POVCorpse(item).MaxDamage;
                            carc.itemName = POVCorpse(item).CorpseItemName;
                            carc.CarcassName = POVCorpse(item).CarcassName;
                            carc.Velocity = item.Velocity * 0.5;
                            item.Velocity = vect(0,0,0);
                            carc.bHidden = False;
                            carc.SetPhysics(PHYS_Falling);
                            carc.SetScaleGlow();
                            if (carc.SetLocation(dropVect))
                            {
                                // must circumvent PutInHand() since it won't allow
                                // things in hand when you're carrying a corpse
                                SetInHandPending(None);
                                item.Destroy();
                                item = None;
                            }
                            else
                                carc.bHidden = True;
                        }
                    }
                }
            }
            else
            {
                if (FastTrace(dropVect))
                {
                    item.DropFrom(dropVect);
                    item.bFixedRotationDir = True;
                    item.RotationRate.Pitch = (32768 - Rand(65536)) * 4.0;
                    item.RotationRate.Yaw = (32768 - Rand(65536)) * 4.0;
                }
            }
        }

        // if we failed to drop it, put it back inHand
        if (item != None)
        {
            if (((inHand == None) || (inHandPending == None)) && (item.Physics != PHYS_Falling))
            {
                PutInHand(item);
                ClientMessage(CannotDropHere);
                bDropped = False;
            }
            else
            {
                item.Instigator = Self;
            }
        }
    }
    else if (CarriedDecoration != None)
    {
        DropDecoration();

        // play a throw anim
        PlayAnim('Attack',,0.1);
    }

    // If the drop failed and we removed the item from the inventory
    // grid, then we need to stick it back where it came from so
    // the inventory doesn't get fucked up.

    if ((bRemovedFromSlots) && (item != None) && (!bDropped))
    {
        //DEUS_EX AMSD Use the function call for this, helps multiplayer
        PlaceItemInSlot(item, itemPosX, itemPosY);
    }

    return bDropped;
}

// ----------------------------------------------------------------------
// RemoveItemDuringConversation()
// ----------------------------------------------------------------------

function RemoveItemDuringConversation(Inventory item)
{
    if (item != None)
    {
        // take it out of our hand
        if (item == inHand)
            PutInHand(None);

        // Make sure it's removed from the inventory grid
        RemoveItemFromSlot(item);

        // Make sure the item is deactivated!
        if (item.IsA('DeusExWeapon'))
        {
            DeusExWeapon(item).ScopeOff();
            DeusExWeapon(item).LaserOff();
        }
        else if (item.IsA('DeusExPickup'))
        {
            // turn it off if it is on
            if (DeusExPickup(item).bActive)
                DeusExPickup(item).Activate();
        }
        
        if (conPlay != None)
            conPlay.SetInHand(None);
    }
}

// ----------------------------------------------------------------------
// WinStats()
// ----------------------------------------------------------------------

exec function WinStats(bool bStatsOn)
{
    if (rootWindow != None)
        rootWindow.ShowStats(bStatsOn);
}

 
// ----------------------------------------------------------------------
// ToggleWinStats()
// ----------------------------------------------------------------------

exec function ToggleWinStats()
{
    if (!bCheatsEnabled)
        return;

    if (rootWindow != None)
        rootWindow.ShowStats(!rootWindow.bShowStats);
}


// ----------------------------------------------------------------------
// WinFrames()
// ----------------------------------------------------------------------

exec function WinFrames(bool bFramesOn)
{
    if (!bCheatsEnabled)
        return;

    if (rootWindow != None)
        rootWindow.ShowFrames(bFramesOn);
}


// ----------------------------------------------------------------------
// ToggleWinFrames()
// ----------------------------------------------------------------------

exec function ToggleWinFrames()
{
    if (!bCheatsEnabled)
        return;

    if (rootWindow != None)
        rootWindow.ShowFrames(!rootWindow.bShowFrames);
}


// ----------------------------------------------------------------------
// ShowClass()
// ----------------------------------------------------------------------

exec function ShowClass(Class<Actor> newClass)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.SetViewClass(newClass);
}


// ----------------------------------------------------------------------
// ShowEyes()
// ----------------------------------------------------------------------

exec function ShowEyes(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowEyes(bShow);
}


// ----------------------------------------------------------------------
// ShowArea()
// ----------------------------------------------------------------------

exec function ShowArea(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowArea(bShow);
}


// ----------------------------------------------------------------------
// ShowCylinder()
// ----------------------------------------------------------------------

exec function ShowCylinder(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowCylinder(bShow);
}


// ----------------------------------------------------------------------
// ShowMesh()
// ----------------------------------------------------------------------

exec function ShowMesh(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowMesh(bShow);
}


// ----------------------------------------------------------------------
// ShowZone()
// ----------------------------------------------------------------------

exec function ShowZone(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowZone(bShow);
}


// ----------------------------------------------------------------------
// ShowLOS()
// ----------------------------------------------------------------------

exec function ShowLOS(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowLOS(bShow);
}


// ----------------------------------------------------------------------
// ShowVisibility()
// ----------------------------------------------------------------------

exec function ShowVisibility(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowVisibility(bShow);
}


// ----------------------------------------------------------------------
// ShowData()
// ----------------------------------------------------------------------

exec function ShowData(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowData(bShow);
}


// ----------------------------------------------------------------------
// ShowEnemyResponse()
// ----------------------------------------------------------------------

exec function ShowEnemyResponse(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowEnemyResponse(bShow);
}


// ----------------------------------------------------------------------
// ShowER()
// ----------------------------------------------------------------------

exec function ShowER(bool bShow)
{
    // Convenience form of ShowEnemyResponse()
    ShowEnemyResponse(bShow);
}


// ----------------------------------------------------------------------
// ShowState()
// ----------------------------------------------------------------------

exec function ShowState(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowState(bShow);
}


// ----------------------------------------------------------------------
// ShowEnemy()
// ----------------------------------------------------------------------

exec function ShowEnemy(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowEnemy(bShow);
}


// ----------------------------------------------------------------------
// ShowInstigator()
// ----------------------------------------------------------------------

exec function ShowInstigator(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowInstigator(bShow);
}


// ----------------------------------------------------------------------
// ShowBase()
// ----------------------------------------------------------------------

exec function ShowBase(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowBase(bShow);
}


// ----------------------------------------------------------------------
// ShowLight()
// ----------------------------------------------------------------------

exec function ShowLight(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowLight(bShow);
}


// ----------------------------------------------------------------------
// ShowDist()
// ----------------------------------------------------------------------

exec function ShowDist(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowDist(bShow);
}


// ----------------------------------------------------------------------
// ShowBindName()
// ----------------------------------------------------------------------

exec function ShowBindName(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowBindName(bShow);
}


// ----------------------------------------------------------------------
// ShowPos()
// ----------------------------------------------------------------------

exec function ShowPos(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowPos(bShow);
}


// ----------------------------------------------------------------------
// ShowHealth()
// ----------------------------------------------------------------------

exec function ShowHealth(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowHealth(bShow);
}


// ----------------------------------------------------------------------
// ShowPhysics()
// ----------------------------------------------------------------------

exec function ShowPhysics(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowPhysics(bShow);
}


// ----------------------------------------------------------------------
// ShowMass()
// ----------------------------------------------------------------------

exec function ShowMass(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowMass(bShow);
}


// ----------------------------------------------------------------------
// ShowVelocity()
// ----------------------------------------------------------------------

exec function ShowVelocity(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowVelocity(bShow);
}


// ----------------------------------------------------------------------
// ShowAcceleration()
// ----------------------------------------------------------------------

exec function ShowAcceleration(bool bShow)
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        if (root.actorDisplay != None)
            root.actorDisplay.ShowAcceleration(bShow);
}


// ----------------------------------------------------------------------
// ShowHud()
// ----------------------------------------------------------------------

exec function ShowHud(bool bShow)
{
    local DeusExRootWindow root;
    root = DeusExRootWindow(rootWindow);
    if (root != None)
        root.ShowHud(bShow);
}

// ----------------------------------------------------------------------
// ToggleObjectBelt()
// ----------------------------------------------------------------------

exec function ToggleObjectBelt()
{
    local DeusExRootWindow root;

    bObjectBeltVisible = !bObjectBeltVisible;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        root.UpdateHud();
}

// ----------------------------------------------------------------------
// ToggleHitDisplay()
// ----------------------------------------------------------------------

exec function ToggleHitDisplay()
{
    local DeusExRootWindow root;

    bHitDisplayVisible = !bHitDisplayVisible;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        root.UpdateHud();
}

// ----------------------------------------------------------------------
// ToggleAmmoDisplay()
// ----------------------------------------------------------------------

exec function ToggleAmmoDisplay()
{
    local DeusExRootWindow root;

    bAmmoDisplayVisible = !bAmmoDisplayVisible;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        root.UpdateHud();
}

// ----------------------------------------------------------------------
// ToggleAugDisplay()
// ----------------------------------------------------------------------

exec function ToggleAugDisplay()
{
    local DeusExRootWindow root;

    bAugDisplayVisible = !bAugDisplayVisible;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        root.UpdateHud();
}

// ----------------------------------------------------------------------
// ToggleCompass()
// ----------------------------------------------------------------------

exec function ToggleCompass()
{
    local DeusExRootWindow root;

    bCompassVisible = !bCompassVisible;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        root.UpdateHud();
}

// ----------------------------------------------------------------------
// ToggleCrosshair()
// ----------------------------------------------------------------------

exec function ToggleCrosshair()
{
    local DeusExRootWindow root;

    bCrosshairVisible = !bCrosshairVisible;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        root.UpdateHud();
}

// ----------------------------------------------------------------------
// ShowInventoryWindow()
// ----------------------------------------------------------------------

exec function ShowInventoryWindow()
{
    if (RestrictInput())
        return;

   if ((Level.NetMode != NM_Standalone) && (bBeltIsMPInventory))
   {
      ClientMessage("Inventory screen disabled in multiplayer");
      return;
   }

    InvokeUIScreen(Class'PersonaScreenInventory');
}

// ----------------------------------------------------------------------
// ShowSkillsWindow()
// ----------------------------------------------------------------------

exec function ShowSkillsWindow()
{
    if (RestrictInput())
        return;

   if ((Level.NetMode != NM_Standalone) && (bBeltIsMPInventory))
   {
      ClientMessage("Skills screen disabled in multiplayer");
      return;
   }

   InvokeUIScreen(Class'PersonaScreenSkills');
}

// ----------------------------------------------------------------------
// ShowHealthWindow()
// ----------------------------------------------------------------------

exec function ShowHealthWindow()
{
    if (RestrictInput())
        return;

   if ((Level.NetMode != NM_Standalone) && (bBeltIsMPInventory))
   {
      ClientMessage("Health screen disabled in multiplayer");
      return;
   }

   InvokeUIScreen(Class'PersonaScreenHealth');
}

// ----------------------------------------------------------------------
// ShowImagesWindow()
// ----------------------------------------------------------------------

exec function ShowImagesWindow()
{
    if (RestrictInput())
        return;

   if ((Level.NetMode != NM_Standalone) && (bBeltIsMPInventory))
   {
      ClientMessage("Images screen disabled in multiplayer");
      return;
   }

   InvokeUIScreen(Class'PersonaScreenImages');
}

// ----------------------------------------------------------------------
// ShowConversationsWindow()
// ----------------------------------------------------------------------

exec function ShowConversationsWindow()
{
    if (RestrictInput())
        return;
       
   if ((Level.NetMode != NM_Standalone) && (bBeltIsMPInventory))
   {
      ClientMessage("Conversations screen disabled in multiplayer");
      return;
   }
   
   InvokeUIScreen(Class'PersonaScreenConversations');
}

// ----------------------------------------------------------------------
// ShowAugmentationsWindow()
// ----------------------------------------------------------------------

exec function ShowAugmentationsWindow()
{
    if (RestrictInput())
        return;

   if ((Level.NetMode != NM_Standalone) && (bBeltIsMPInventory))
   {
      ClientMessage("Augmentations screen disabled in multiplayer");
      return;
   }

   InvokeUIScreen(Class'PersonaScreenAugmentations');
}

// ----------------------------------------------------------------------
// ShowGoalsWindow()
// ----------------------------------------------------------------------

exec function ShowGoalsWindow()
{
    if (RestrictInput())
        return;
       
   if ((Level.NetMode != NM_Standalone) && (bBeltIsMPInventory))
   {
      ClientMessage("Goals screen disabled in multiplayer");
      return;
   }
   
   InvokeUIScreen(Class'PersonaScreenGoals');
}

// ----------------------------------------------------------------------
// ShowLogsWindow()
// ----------------------------------------------------------------------

exec function ShowLogsWindow()
{
    if (RestrictInput())
        return;

   if ((Level.NetMode != NM_Standalone) && (bBeltIsMPInventory))
   {
      ClientMessage("Logs screen disabled in multiplayer");
      return;
   }

   InvokeUIScreen(Class'PersonaScreenLogs');
}

// ----------------------------------------------------------------------
// ShowAugmentationAddWindow()
// ----------------------------------------------------------------------

exec function ShowAugmentationAddWindow()
{
    if (RestrictInput())
        return;

    InvokeUIScreen(Class'HUDMedBotAddAugsScreen');
}

// ----------------------------------------------------------------------
// ShowQuotesWindow()
// ----------------------------------------------------------------------

exec function ShowQuotesWindow()
{
    if (!bCheatsEnabled)
        return;

    InvokeUIScreen(Class'QuotesWindow');
}

// ----------------------------------------------------------------------
// ShowRGBDialog()
// ----------------------------------------------------------------------

exec function ShowRGBDialog()
{
    local DeusExRootWindow root;

    if (!bCheatsEnabled)
        return;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        root.PushWindow(Class'MenuScreenRGB');
}

// ----------------------------------------------------------------------
// ActivateBelt()
// ----------------------------------------------------------------------

exec function ActivateBelt(int objectNum)
{
    local DeusExRootWindow root;

    if (RestrictInput())
        return;

    if ((Level.NetMode != NM_Standalone) && bBuySkills)
    {
        root = DeusExRootWindow(rootWindow);
        if ( root != None )
        {
            if ( root.hud.hms.OverrideBelt( Self, objectNum ))
                return;
        }
    }

    if (CarriedDecoration == None)
    {
        root = DeusExRootWindow(rootWindow);
        if (root != None)
            root.ActivateObjectInBelt(objectNum);
    }
}

// ----------------------------------------------------------------------
// NextBeltItem()
// ----------------------------------------------------------------------

exec function NextBeltItem()
{
    local DeusExRootWindow root;
    local int slot, startSlot;

    if (RestrictInput())
        return;

    if (CarriedDecoration == None)
    {
        slot = 0;
        root = DeusExRootWindow(rootWindow);
        if (root != None)
        {
            if (ClientInHandPending != None)
                slot = ClientInHandPending.beltPos;
            else if (inHandPending != None)
                slot = inHandPending.beltPos;
            else if (inHand != None)
                slot = inHand.beltPos;

            startSlot = slot;
            do
            {
                if (++slot >= 10)
                    slot = 0;
            }
            until (root.ActivateObjectInBelt(slot) || (startSlot == slot));

            clientInHandPending = root.hud.belt.GetObjectFromBelt(slot);
        }
    }
}

// ----------------------------------------------------------------------
// PrevBeltItem()
// ----------------------------------------------------------------------

exec function PrevBeltItem()
{
    local DeusExRootWindow root;
    local int slot, startSlot;

    if (RestrictInput())
        return;

    if (CarriedDecoration == None)
    {
        slot = 1;
        root = DeusExRootWindow(rootWindow);
        if (root != None)
        {
            if (ClientInHandPending != None)
                slot = ClientInHandPending.beltPos;
            else  if (inHandPending != None)
                slot = inHandPending.beltPos;
            else if (inHand != None)
                slot = inHand.beltPos;

            startSlot = slot;
            do
            {
                if (--slot <= -1)
                    slot = 9;
            }
            until (root.ActivateObjectInBelt(slot) || (startSlot == slot));

            clientInHandPending = root.hud.belt.GetObjectFromBelt(slot);
        }
    }
}

// ----------------------------------------------------------------------
// ShowMainMenu()
// ----------------------------------------------------------------------

exec function ShowMainMenu()
{
    local DeusExRootWindow root;
    local DeusExLevelInfo info;
    local MissionEndgame Script;

    if (bIgnoreNextShowMenu)
    {
        bIgnoreNextShowMenu = False;
        return;
    }

    info = GetLevelInfo();

    // Special case baby!
    // 
    // If the Intro map is loaded and we get here, that means the player
    // pressed Escape and we want to either A) start a new game 
    // or B) return to the dx.dx screen.  Either way we're going to 
    // abort the Intro by doing this. 
    //
    // If this is one of the Endgames (which have a mission # of 99)
    // then we also want to call the Endgame's "FinishCinematic" 
    // function

    // force the texture caches to flush
    ConsoleCommand("FLUSH");

    if ((info != None) && (info.MissionNumber == 98)) 
    {
        bIgnoreNextShowMenu = True;
        PostIntro();
    }
    else if ((info != None) && (info.MissionNumber == 99))
    {
        foreach AllActors(class'MissionEndgame', Script)
            break;

        if (Script != None)
            Script.FinishCinematic();
    }
    else
    {
        root = DeusExRootWindow(rootWindow);
        if (root != None)
            root.InvokeMenu(Class'MenuMain');
    }
}

// ----------------------------------------------------------------------
// PostIntro()
// ----------------------------------------------------------------------

function PostIntro()
{
    if (bStartNewGameAfterIntro)
    {
        bStartNewGameAfterIntro = False;
        StartNewGame(strStartMap);
    }
    else
    {
        Level.Game.SendPlayer(Self, "dxonly");
    }
}

// ----------------------------------------------------------------------
// EditFlags()
//
// Displays the Flag Edit dialog
// ----------------------------------------------------------------------

exec function EditFlags()
{
    if (!bCheatsEnabled)
        return;

    InvokeUIScreen(Class'FlagEditWindow');
}

// ----------------------------------------------------------------------
// InvokeConWindow()
//
// Displays the Invoke Conversation Window
// ----------------------------------------------------------------------

exec function InvokeConWindow()
{
    if (!bCheatsEnabled)
        return;

    InvokeUIScreen(Class'InvokeConWindow');
}

// ----------------------------------------------------------------------
// LoadMap()
//
// Displays the Load Map dialog
// ----------------------------------------------------------------------

exec function LoadMap()
{
    if (!bCheatsEnabled)
        return;

    InvokeUIScreen(Class'LoadMapWindow');
}

// ----------------------------------------------------------------------
// Overrides from PlayerPawn
// ----------------------------------------------------------------------

exec function Walk()
{
    if (RestrictInput())
        return;

    if (!bCheatsEnabled)
        return;

    Super.Walk();
}

exec function Fly()
{
    if (RestrictInput())
        return;

    if (!bCheatsEnabled)
        return;

    Super.Fly();
}

exec function Ghost()
{
    if (RestrictInput())
        return;

    if (!bCheatsEnabled)
        return;

    Super.Ghost();
}

exec function Fire(optional float F)
{
    if (RestrictInput())
    {
        if (bHidden)
            ShowMainMenu();
        return;
    }

    Super.Fire(F);
}

// ----------------------------------------------------------------------
// Tantalus()
//
// Instantly kills/destroys the object directly in front of the player
// (just like the Tantalus Field in Star Trek)
// ----------------------------------------------------------------------

exec function Tantalus()
{
    local Actor            hitActor;
    local Vector           hitLocation, hitNormal;
    local Vector           position, line;
    local ScriptedPawn     hitPawn;
    local DeusExMover      hitMover;
    local DeusExDecoration hitDecoration;
    local bool             bTakeDamage;
    local int              damage;

    if (!bCheatsEnabled)
        return;

    bTakeDamage = false;
    damage      = 1;
    position    = Location;
    position.Z += BaseEyeHeight;
    line        = Vector(ViewRotation) * 4000;

    hitActor = Trace(hitLocation, hitNormal, position+line, position, true);
    if (hitActor != None)
    {
        hitMover = DeusExMover(hitActor);
        hitPawn = ScriptedPawn(hitActor);
        hitDecoration = DeusExDecoration(hitActor);
        if (hitMover != None)
        {
            if (hitMover.bBreakable)
            {
                hitMover.doorStrength = 0;
                bTakeDamage = true;
            }
        }
        else if (hitPawn != None)
        {
            if (!hitPawn.bInvincible)
            {
                hitPawn.HealthHead     = 0;
                hitPawn.HealthTorso    = 0;
                hitPawn.HealthLegLeft  = 0;
                hitPawn.HealthLegRight = 0;
                hitPawn.HealthArmLeft  = 0;
                hitPawn.HealthArmRight = 0;
                hitPawn.Health         = 0;
                bTakeDamage = true;
            }
        }
        else if (hitDecoration != None)
        {
            if (!hitDecoration.bInvincible)
            {
                hitDecoration.HitPoints = 0;
                bTakeDamage = true;
            }
        }
        else if (hitActor != Level)
        {
            damage = 5000;
            bTakeDamage = true;
        }
    }

    if (bTakeDamage)
        hitActor.TakeDamage(damage, self, hitLocation, line, 'Tantalus');
}

// ----------------------------------------------------------------------
// OpenSesame()
//
// Opens any door immediately in front of you, locked or not
// ----------------------------------------------------------------------

exec function OpenSesame()
{
    local Actor       hitActor;
    local Vector      hitLocation, hitNormal;
    local Vector      position, line;
    local DeusExMover hitMover;
    local DeusExMover triggerMover;
    local HackableDevices device;

    if (!bCheatsEnabled)
        return;

    position    = Location;
    position.Z += BaseEyeHeight;
    line        = Vector(ViewRotation) * 4000;

    hitActor = Trace(hitLocation, hitNormal, position+line, position, true);
    hitMover = DeusExMover(hitActor);
    device   = HackableDevices(hitActor);
    if (hitMover != None)
    {
        if ((hitMover.Tag != '') && (hitMover.Tag != 'DeusExMover'))
        {
            foreach AllActors(class'DeusExMover', triggerMover, hitMover.Tag)
            {
                triggerMover.bLocked = false;
                triggerMover.Trigger(self, self);
            }
        }
        else
        {
            hitMover.bLocked = false;
            hitMover.Trigger(self, self);
        }
    }
    else if (device != None)
    {
        if (device.bHackable)
        {
            if (device.hackStrength > 0)
            {
                device.hackStrength = 0;
                device.HackAction(self, true);
            }
        }
    }
}

// ----------------------------------------------------------------------
// Legend()
//
// Displays the "Behind The Curtain" menu
// ----------------------------------------------------------------------

exec function Legend()
{
    if (!bCheatsEnabled)
        return;

    InvokeUIScreen(Class'BehindTheCurtain');
}

// ----------------------------------------------------------------------
// AddInventory()
// ----------------------------------------------------------------------

function bool AddInventory(inventory item)
{
    local bool retval;
    local DeusExRootWindow root;

    retval = super.AddInventory(item);

    // Force the object be added to the object belt
    // unless it's ammo
    //
    // Don't add Ammo and don't add Images!

    if ((item != None) && !item.IsA('Ammo') && (!item.IsA('DataVaultImage')) && (!item.IsA('Credits')))
    {
        root = DeusExRootWindow(rootWindow);

        if ( item.bInObjectBelt )
        {
            if (root != None)
            {
                root.hud.belt.AddObjectToBelt(item, item.beltPos, True);
            }
        }

        if (retval)
        {
            if (root != None)
         {
                root.AddInventory(item);
         }
        }
    }

    return (retval);
}

// ----------------------------------------------------------------------
// DeleteInventory()
// ----------------------------------------------------------------------

function bool DeleteInventory(inventory item)
{
    local bool retval;
    local DeusExRootWindow root;
    local PersonaScreenInventory winInv;

    // If the item was inHand, clear the inHand
    if (inHand == item)
    {
        SetInHand(None);
        SetInHandPending(None);
    }

    // Make sure the item is removed from the inventory grid
    RemoveItemFromSlot(item);

    root = DeusExRootWindow(rootWindow);

    if (root != None)
    {
        // If the inventory screen is active, we need to send notification
        // that the item is being removed
        winInv = PersonaScreenInventory(root.GetTopWindow());
        if (winInv != None)
            winInv.InventoryDeleted(item);

        // Remove the item from the object belt
        if (root != None)
            root.DeleteInventory(item);
      else //In multiplayer, we often don't have a root window when creating corpse, so hand delete
      {
         item.bInObjectBelt = false;
         item.beltPos = -1;
      }
    }

    return Super.DeleteInventory(item);
}

// ----------------------------------------------------------------------
// JoltView()
// ----------------------------------------------------------------------

event JoltView(float newJoltMagnitude)
{
    if (Abs(JoltMagnitude) < Abs(newJoltMagnitude))
        JoltMagnitude = newJoltMagnitude;
}

// ----------------------------------------------------------------------
// UpdateEyeHeight()
// ----------------------------------------------------------------------

event UpdateEyeHeight(float DeltaTime)
{
    Super.UpdateEyeHeight(DeltaTime);

    if (JoltMagnitude != 0)
    {
        if ((Physics == PHYS_Walking) && (Bob != 0))
            EyeHeight += (JoltMagnitude * 5);
        JoltMagnitude = 0;
    }
}

// ----------------------------------------------------------------------
// PlayerCalcView()
// ----------------------------------------------------------------------

event PlayerCalcView( out actor ViewActor, out vector CameraLocation, out rotator CameraRotation )
{
    // check for spy drone and freeze player's view
    if (bSpyDroneActive)
    {
        if (aDrone != None)
        {
            // First-person view.
            CameraLocation = Location;
            CameraLocation.Z += EyeHeight;
            CameraLocation += WalkBob;
            return;
        }
    }

    // Check if we're in first-person view or third-person.  If we're in first-person then
    // we'll just render the normal camera view.  Otherwise we want to place the camera
    // as directed by the conPlay.cameraInfo object.

    if ( bBehindView && (!InConversation()) )
    {
        Super.PlayerCalcView(ViewActor, CameraLocation, CameraRotation);
        return;
    }

    if ( (!InConversation()) || ( conPlay.GetDisplayMode() == DM_FirstPerson ) )
    {
        // First-person view.
        ViewActor = Self;
        CameraRotation = ViewRotation;
        CameraLocation = Location;
        CameraLocation.Z += EyeHeight;
        CameraLocation += WalkBob;
        return;
    }

    // Allow the ConCamera object to calculate the camera position and 
    // rotation for us (in other words, take this sloppy routine and 
    // hide it elsewhere).

    if (conPlay.cameraInfo.CalculateCameraPosition(ViewActor, CameraLocation, CameraRotation) == False)
        Super.PlayerCalcView(ViewActor, CameraLocation, CameraRotation);
}


// ----------------------------------------------------------------------
// PlayerInput()
// ----------------------------------------------------------------------

event PlayerInput( float DeltaTime )
{
    if (!InConversation())
        Super.PlayerInput(DeltaTime);
}

// ----------------------------------------------------------------------
// state Conversation
// ----------------------------------------------------------------------

state Conversation
{
ignores SeePlayer, HearNoise, Bump;

    event PlayerTick(float deltaTime)
    {
        local rotator tempRot;
        local float   yawDelta;

        UpdateInHand();
        UpdateDynamicMusic(deltaTime);

        DrugEffects(deltaTime);
        Bleed(deltaTime);
        MaintainEnergy(deltaTime);

        // must update viewflash manually incase a flash happens during a convo
        ViewFlash(deltaTime);

        // Check if player has walked outside a first-person convo.
        CheckActiveConversationRadius();
    
        // Check if all the people involved in a conversation are 
        // still within a reasonable radius.
        CheckActorDistances();

        Super.PlayerTick(deltaTime);
        LipSynch(deltaTime);

        // Keep turning towards the person we're speaking to
        if (ConversationActor != None)
        {
            LookAtActor(ConversationActor, true, true, true, 0, 0.5);

            // Hacky way to force the player to turn...
            tempRot = rot(0,0,0);
            tempRot.Yaw = (DesiredRotation.Yaw - Rotation.Yaw) & 65535;
            if (tempRot.Yaw > 32767)
                tempRot.Yaw -= 65536;
            yawDelta = RotationRate.Yaw * deltaTime;
            if (tempRot.Yaw > yawDelta)
                tempRot.Yaw = yawDelta;
            else if (tempRot.Yaw < -yawDelta)
                tempRot.Yaw = -yawDelta;
            SetRotation(Rotation + tempRot);
        }

        // Update Time Played
        UpdateTimePlayed(deltaTime);
    }

    function LoopHeadConvoAnim()
    {
    }

    function EndState()
    {
        conPlay = None;

        // Re-enable the PC's detectability
        MakePlayerIgnored(false);

        MoveTarget = None;
        bBehindView = false;
        StopBlendAnims();
        ConversationActor = None;
    }

Begin:
    // Make sure we're stopped
    Velocity.X = 0;
    Velocity.Y = 0;
    Velocity.Z = 0;

    Acceleration = Velocity;

    PlayRising();

    // Make sure the player isn't on fire!
    if (bOnFire)
        ExtinguishFire();

    // Make sure the PC can't be attacked while in conversation
    MakePlayerIgnored(true);

    LookAtActor(conPlay.startActor, true, false, true, 0, 0.5);

    SetRotation(DesiredRotation);

    PlayTurning();
//	TurnToward(conPlay.startActor);
//	TweenToWaiting(0.1);
//	FinishAnim();

    if (!conPlay.StartConversation(Self))
    {
        AbortConversation(True);
    }
    else
    {
        // Put away whatever the PC may be holding
        conPlay.SetInHand(InHand);
        PutInHand(None);
        UpdateInHand();

        if ( conPlay.GetDisplayMode() == DM_ThirdPerson )
            bBehindView = true; 
    }
}

// ----------------------------------------------------------------------
// InConversation()
//
// Returns True if the player is currently engaged in conversation
// ----------------------------------------------------------------------

function bool InConversation()
{
    if ( conPlay == None )
    {
        return False;
    }
    else
    {
        if (conPlay.con != None)
            return ((conPlay.con.bFirstPerson == False) && (!conPlay.GetForcePlay()));
        else
            return False;
    }
}

// ----------------------------------------------------------------------
// CanStartConversation()
//
// Returns true if we can start a conversation.  Basically this means 
// that 
//
// 1) If in conversation, bCannotBeInterrutped set to False
// 2) If in conversation, if we're not in a third-person convo
// 3) The player isn't in 'bForceDuck' mode
// 4) The player isn't DEAD!
// 5) The player isn't swimming
// 6) The player isn't CheatFlying (ghost)
// 7) The player isn't in PHYS_Falling
// 8) The game is in 'bPlayersOnly' mode
// 9) UI screen of some sort isn't presently active.
// ----------------------------------------------------------------------

function bool CanStartConversation()
{
    if  (((conPlay != None) && (conPlay.CanInterrupt() == False)) ||
        ((conPlay != None) && (conPlay.con.bFirstPerson != True)) ||
         (( bForceDuck == True ) && ((HealthLegLeft > 0) || (HealthLegRight > 0))) ||
         ( IsInState('Dying') ) ||
         ( IsInState('PlayerSwimming') ) ||  
         ( IsInState('CheatFlying') ) ||
         ( Physics == PHYS_Falling ) || 
         ( Level.bPlayersOnly ) ||
         (!DeusExRootWindow(rootWindow).CanStartConversation()))
        return False;
    else    
        return True;
}

// ----------------------------------------------------------------------
// GetDisplayName()
//
// Returns a name that can be displayed in the conversation.  
//
// The first time we speak to someone we'll use the Unfamiliar name.
// For subsequent conversations, use the Familiar name.  As a fallback,
// the BindName will be used if both of the other two fields
// are blank.
//
// If this is a DeusExDecoration and the Familiar/Unfamiliar names
// are blank, then use the decoration's ItemName instead.  This is 
// for use in the FrobDisplayWindow.
// ----------------------------------------------------------------------

function String GetDisplayName(Actor actor, optional Bool bUseFamiliar)
{
    local String displayName;

    // Sanity check
    if ((actor == None) || (player == None) || (rootWindow == None))
        return "";

    // If we've spoken to this person already, use the 
    // Familiar Name
    if ((actor.FamiliarName != "") && ((actor.LastConEndTime > 0) || (bUseFamiliar)))
        displayName = actor.FamiliarName;

    if ((displayName == "") && (actor.UnfamiliarName != ""))
        displayName = actor.UnfamiliarName;

    if (displayName == "")
    {
        if (actor.IsA('DeusExDecoration'))
            displayName = DeusExDecoration(actor).itemName;
        else
            displayName = actor.BindName;
    }

    return displayName;
}

// ----------------------------------------------------------------------
// EndConversation()
//
// Called by ConPlay when a conversation has finished.
// ----------------------------------------------------------------------

function EndConversation()
{
    local DeusExLevelInfo info;

    Super.EndConversation();

    // If we're in a bForcePlay (cinematic) conversation,
    // force the CinematicWindow to be displayd
    if ((conPlay != None) && (conPlay.GetForcePlay()))
    {
        if (DeusExRootWindow(rootWindow) != None)
            DeusExRootWindow(rootWindow).NewChild(class'CinematicWindow');
    }

    conPlay = None;

    // Check to see if we need to resume any DataLinks that may have
    // been aborted when we started this conversation
    ResumeDataLinks();

    StopBlendAnims();

    // We might already be dead at this point (someone drop a LAM before
    // entering the conversation?) so we want to make sure the player
    // doesn't suddenly jump into a non-DEATH state.
    //
    // Also make sure the player is actually in the Conversation state
    // before attempting to kick him out of it.

    if ((Health > 0) && ((IsInState('Conversation')) || (IsInState('FirstPersonConversation')) || (NextState == 'Interpolating')))
    {
        if (NextState == '')
            GotoState('PlayerWalking');
        else
            GotoState(NextState);
    }
}

// ----------------------------------------------------------------------
// ResumeDataLinks()
// ----------------------------------------------------------------------

function ResumeDataLinks()
{
    if ( dataLinkPlay != None )
        dataLinkPlay.ResumeDataLinks();
}

// ----------------------------------------------------------------------
// AbortConversation()
// ----------------------------------------------------------------------

function AbortConversation(optional bool bNoPlayedFlag)
{
    if (conPlay != None)
        conPlay.TerminateConversation(False, bNoPlayedFlag);
}

// ----------------------------------------------------------------------
// StartConversationByName()
//
// Starts a conversation by looking for the name passed in.  
//
// Calls StartConversation() if a match is found.
// ----------------------------------------------------------------------

function bool StartConversationByName(
    Name conName, 
    Actor conOwner, 
    optional bool bAvoidState, 
    optional bool bForcePlay
    )
{
    local ConListItem conListItem;
    local Conversation con;
    local Int  dist;
    local Bool bConversationStarted;

    bConversationStarted = False;

    if (conOwner == None)
        return False;

    conListItem = ConListItem(conOwner.conListItems);

    while( conListItem != None )
    {
        if ( conListItem.con.conName == conName )
        {
            con = conListItem.con;          
            break;
        }

        conListItem = conListItem.next;
    }

    // Now check to see that we're in a respectable radius.
    if (con != None)
    {
        dist = VSize(Location - conOwner.Location);

        // 800 = default sound radius, from unscript.cpp
        // 
        // If "bForcePlay" is set, then force the conversation
        // to play!

        if ((dist <= 800) || (bForcePlay))
            bConversationStarted = StartConversation(conOwner, IM_Named, con, bAvoidState, bForcePlay);
    }

    return bConversationStarted;
}

// ----------------------------------------------------------------------
// StartAIBarkConversation()
//
// Starts an AI Bark conversation, which really isn't a conversation
// as much as a simple bark.  
// ----------------------------------------------------------------------

function bool StartAIBarkConversation(
    Actor conOwner,
    EBarkModes barkMode
    )
{
    if ((conOwner == None) || (conOwner.conListItems == None) || (barkManager == None) ||
        ((conPlay != None) && (conPlay.con.bFirstPerson != True)))
        return False;
    else
        return (barkManager.StartBark(DeusExRootWindow(rootWindow), ScriptedPawn(conOwner), barkMode));
}

// ----------------------------------------------------------------------
// StartConversation()
// 
// Checks to see if a valid conversation exists for this moment in time
// between the ScriptedPawn and the PC.  If so, then it triggers the 
// conversation system and returns TRUE when finished.
// ----------------------------------------------------------------------

function bool StartConversation(
    Actor invokeActor, 
    EInvokeMethod invokeMethod, 
    optional Conversation con,
    optional bool bAvoidState,
    optional bool bForcePlay
    )
{
    local DeusExRootWindow root;

    root = DeusExRootWindow(rootWindow);

    // First check to see the actor has any conversations or if for some
    // other reason we're unable to start a conversation (typically if 
    // we're alread in a conversation or there's a UI screen visible)

    if ((!bForcePlay) && ((invokeActor.conListItems == None) || (!CanStartConversation())))
        return False;

    // Make sure the other actor can converse
    if ((!bForcePlay) && ((ScriptedPawn(invokeActor) != None) && (!ScriptedPawn(invokeActor).CanConverse())))
        return False;

    // If we have a conversation passed in, use it.  Otherwise check to see
    // if the passed in actor actually has a valid conversation that can be
    // started.

    if ( con == None )
        con = GetActiveConversation(invokeActor, invokeMethod);

    // If we have a conversation, put the actor into "Conversation Mode".
    // Otherwise just return false.
    //
    // TODO: Scan through the conversation and put *ALL* actors involved
    //       in the conversation into the "Conversation" state??

    if ( con != None )
    {
        // Check to see if this conversation is already playing.  If so,
        // then don't start it again.  This prevents a multi-bark conversation
        // from being abused.
        if ((conPlay != None) && (conPlay.con == con))
            return False;

        // Now check to see if there's a conversation playing that is owned
        // by the InvokeActor *and* the player has a speaking part *and*
        // it's a first-person convo, in which case we want to abort here.
        if (((conPlay != None) && (conPlay.invokeActor == invokeActor)) && 
            (conPlay.con.bFirstPerson) &&
            (conPlay.con.IsSpeakingActor(Self)))
            return False;

        // Check if the person we're trying to start the conversation 
        // with is a Foe and this is a Third-Person conversation.  
        // If so, ABORT!
        if ((!bForcePlay) && ((!con.bFirstPerson) && (ScriptedPawn(invokeActor) != None) && (ScriptedPawn(invokeActor).GetPawnAllianceType(Self) == ALLIANCE_Hostile)))
            return False;

        // If the player is involved in this conversation, make sure the 
        // scriptedpawn even WANTS to converse with the player.
        //
        // I have put a hack in here, if "con.bCanBeInterrupted" 
        // (which is no longer used as intended) is set, then don't 
        // call the ScriptedPawn::CanConverseWithPlayer() function

        if ((!bForcePlay) && ((con.IsSpeakingActor(Self)) && (!con.bCanBeInterrupted) && (ScriptedPawn(invokeActor) != None) && (!ScriptedPawn(invokeActor).CanConverseWithPlayer(Self))))
            return False;

        // Hack alert!  If this is a Bark conversation (as denoted by the 
        // conversation name, since we don't have a field in ConEdit), 
        // then force this conversation to be first-person
        if (Left(con.conName, Len(con.conOwnerName) + 5) == (con.conOwnerName $ "_Bark"))
            con.bFirstPerson = True;

        // Make sure the player isn't ducking.  If the player can't rise
        // to start a third-person conversation (blocked by geometry) then 
        // immediately abort the conversation, as this can create all 
        // sorts of complications (such as the player standing through
        // geometry!!)

        if ((!con.bFirstPerson) && (ResetBasedPawnSize() == False))
            return False;

        // If ConPlay exists, end the current conversation playing
        if (conPlay != None)
        {
            // If we're already playing a third-person conversation, don't interrupt with
            // another *radius* induced conversation (frobbing is okay, though).
            if ((conPlay.con != None) && (conPlay.con.bFirstPerson) && (invokeMethod == IM_Radius))
                return False;

            conPlay.InterruptConversation();
            conPlay.TerminateConversation();
        }

        // If this is a first-person conversation _and_ a DataLink is already
        // playing, then abort.  We don't want to give the user any more 
        // distractions while a DL is playing, since they're pretty important.
        if ( dataLinkPlay != None )
        {
            if (con.bFirstPerson)
                return False;
            else
                dataLinkPlay.AbortAndSaveHistory();
        }

        // Found an active conversation, so start it
        conPlay = Spawn(class'ConPlay');
        conPlay.SetStartActor(invokeActor);
        conPlay.SetConversation(con);
        conPlay.SetForcePlay(bForcePlay);
        conPlay.SetInitialRadius(VSize(Location - invokeActor.Location));

        // If this conversation was invoked with IM_Named, then save away
        // the current radius so we don't abort until we get outside 
        // of this radius + 100.
        if ((invokeMethod == IM_Named) || (invokeMethod == IM_Frob))
        {
            conPlay.SetOriginalRadius(con.radiusDistance);
            con.radiusDistance = VSize(invokeActor.Location - Location);
        }

        // If the invoking actor is a ScriptedPawn, then force this person 
        // into the conversation state
        if ((!bForcePlay) && (ScriptedPawn(invokeActor) != None ))
            ScriptedPawn(invokeActor).EnterConversationState(con.bFirstPerson, bAvoidState);

        // Do the same if this is a DeusExDecoration
        if ((!bForcePlay) && (DeusExDecoration(invokeActor) != None ))
            DeusExDecoration(invokeActor).EnterConversationState(con.bFirstPerson, bAvoidState);

        // If this is a third-person convo, we're pretty much going to 
        // pause the game.  If this is a first-person convo, then just 
        // keep on going..
        //
        // If this is a third-person convo *AND* 'bForcePlay' == True, 
        // then use first-person mode, as we're playing an intro/endgame
        // sequence and we can't have the player in the convo state (bad bad bad!)

        if ((!con.bFirstPerson) && (!bForcePlay))
        {
            GotoState('Conversation');
        }
        else
        {
            if (!conPlay.StartConversation(Self, invokeActor, bForcePlay))
            {
                AbortConversation(True);
            }
        }

        return True;
    }
    else
    {
        return False;
    }
}

// ----------------------------------------------------------------------
// GetActiveConversation()
//
// This routine searches all the conversations in this chain until it 
// finds one that is valid for this situation.  It returns the 
// conversation or None if none are found.
// ----------------------------------------------------------------------

function Conversation GetActiveConversation( Actor invokeActor, EInvokeMethod invokeMethod )
{
    local ConListItem conListItem;
    local Conversation con;
    local Name flagName;
    local bool bAbortConversation;

    // If we don't have a valid invokeActor or the flagbase
    // hasn't yet been initialized, immediately abort.
    if ((invokeActor == None) || (flagBase == None))
        return None;

    bAbortConversation = True;

    // Force there to be a one second minimum between conversations 
    // with the same NPC
    if ((invokeActor.LastConEndTime != 0) && 
        ((Level.TimeSeconds - invokeActor.LastConEndTime) < 1.0))
        return None;

    // In a loop, go through the conversations, checking each.
    conListItem = ConListItem(invokeActor.ConListItems);

    while ( conListItem != None )
    {
        con = conListItem.con;

        bAbortConversation = False;

        // Ignore Bark conversations, as these are started manually
        // by the AI system.  Do this by checking to see if the first
        // part of the conversation name is in the form, 
        //
        // ConversationOwner_Bark

        if (Left(con.conName, Len(con.conOwnerName) + 5) == (con.conOwnerName $ "_Bark"))
            bAbortConversation = True;

        if (!bAbortConversation)
        {
            // Now check the invocation method to make sure
            // it matches what was passed in

            switch( invokeMethod )
            {
                // Removed Bump conversation starting functionality, all convos
                // must now be "Frobbed" to start (excepting Radius, of course).
                case IM_Bump:
                case IM_Frob:
                    bAbortConversation = !(con.bInvokeFrob || con.bInvokeBump);
                    break;

                case IM_Sight:
                    bAbortConversation = !con.bInvokeSight;
                    break;

                case IM_Radius:
                    if ( con.bInvokeRadius )
                    {
                        // Calculate the distance between the player and the owner
                        // and if the player is inside that radius, we've passed 
                        // this check.

                        bAbortConversation = !CheckConversationInvokeRadius(invokeActor, con);

                        // First check to make sure that at least 10 seconds have passed
                        // before playing a radius-induced conversation after a letterbox
                        // conversation with the player
                        //
                        // Check:
                        //  
                        // 1.  Player finished letterbox convo in last 10 seconds
                        // 2.  Conversation was with this NPC
                        // 3.  This new radius conversation is with same NPC.

                        if ((!bAbortConversation) && 
                            ((Level.TimeSeconds - lastThirdPersonConvoTime) < 10) && 
                            (lastThirdPersonConvoActor == invokeActor))
                            bAbortConversation = True;

                        // Now check if this conversation ended in the last ten seconds or so
                        // We want to prevent the user from getting trapped inside the same 
                        // radius conversation 
                        
                        if ((!bAbortConversation) && (con.lastPlayedTime > 0))
                            bAbortConversation = ((Level.TimeSeconds - con.lastPlayedTime) < 10);

                        // Now check to see if the player just ended a radius, third-person
                        // conversation with this NPC in the last 5 seconds.  If so, punt, 
                        // because we don't want these to chain together too quickly.

                        if ((!bAbortConversation) &&
                            ((Level.TimeSeconds - lastFirstPersonConvoTime) < 5) && 
                            (lastFirstPersonConvoActor == invokeActor))
                            bAbortConversation = True;
                    }
                    else
                    {
                        bAbortConversation = True;
                    }
                    break;

                case IM_Other:
                default:
                    break;
            }
        }

        // Now check to see if these two actors are too far apart on their Z
        // axis so we don't get conversations triggered when someone jumps on
        // someone else, or when actors are on two different levels.

        if (!bAbortConversation)
        {
            bAbortConversation = !CheckConversationHeightDifference(invokeActor, 20);

            // If the height check failed, look to see if the actor has a LOS view
            // to the player in which case we'll allow the conversation to continue
            
            if (bAbortConversation)
                bAbortConversation = !CanActorSeePlayer(invokeActor);
        }

        // Check if this conversation is only to be played once 
        if (( !bAbortConversation ) && ( con.bDisplayOnce ))
        {
            flagName = rootWindow.StringToName(con.conName $ "_Played");        
            bAbortConversation = (flagBase.GetBool(flagName) == True);
        }

        if ( !bAbortConversation )
        {
            // Then check to make sure all the flags that need to be
            // set are.

            bAbortConversation = !CheckFlagRefs(con.flagRefList);
        }

        if ( !bAbortConversation )
            break;
    
        conListItem = conListItem.next;
    }

    if (bAbortConversation)
        return None;
    else
        return con;
}

// ----------------------------------------------------------------------
// CheckConversationInvokeRadius()
//
// Returns True if this conversation can be invoked given the 
// invoking actor and the conversation passed in.
// ----------------------------------------------------------------------

function bool CheckConversationInvokeRadius(Actor invokeActor, Conversation con)
{
    local Int  invokeRadius;
    local Int  dist;

    dist = VSize(Location - invokeActor.Location);

    invokeRadius = Max(16, con.radiusDistance);

    return (dist <= invokeRadius);
}

// ----------------------------------------------------------------------
// CheckConversationHeightDifference()
//
// Checks to make sure the player and the invokeActor are fairly close
// to each other on the Z Plane.  Returns True if they are an 
// acceptable distance, otherwise returns False.
// ----------------------------------------------------------------------

function bool CheckConversationHeightDifference(Actor invokeActor, int heightOffset)
{
    local Int dist;

    dist = Abs(Location.Z - invokeActor.Location.Z) - Abs(Default.CollisionHeight - CollisionHeight);

    if (dist > (Abs(CollisionHeight - invokeActor.CollisionHeight) + heightOffset))
        return False;
    else
        return True;
}
    
// ----------------------------------------------------------------------
// CanActorSeePlayer()
// ----------------------------------------------------------------------

function bool CanActorSeePlayer(Actor invokeActor)
{
    return FastTrace(invokeActor.Location);
}

// ----------------------------------------------------------------------
// CheckActiveConversationRadius()
//
// If there's a first-person conversation active, checks to make sure 
// that the player has not walked far away from the conversation owner.
// If so, the conversation is aborted.
// ----------------------------------------------------------------------

function CheckActiveConversationRadius()
{
    local int checkRadius;

    // Ignore if conPlay.GetForcePlay() returns True

    if ((conPlay != None) && (!conPlay.GetForcePlay()) && (conPlay.ConversationStarted()) && (conPlay.displayMode == DM_FirstPerson) && (conPlay.StartActor != None))
    {
        // If this was invoked via a radius, then check to make sure the player doesn't 
        // exceed that radius plus 

        if (conPlay.con.bInvokeRadius) 
            checkRadius = conPlay.con.radiusDistance + 100;
        else
            checkRadius = 300;

        // Add the collisioncylinder since some objects are wider than others
        checkRadius += conPlay.StartActor.CollisionRadius;

        if (VSize(conPlay.startActor.Location - Location) > checkRadius)
        {
            // Abort the conversation
            conPlay.TerminateConversation(True);
        }
    }
}

// ----------------------------------------------------------------------
// CheckActorDistances()
//
// Checks to see how far all the actors are away from each other 
// to make sure the conversation should continue.
// ----------------------------------------------------------------------

function bool CheckActorDistances()
{
    if ((conPlay != None) && (!conPlay.GetForcePlay()) && (conPlay.ConversationStarted()) && (conPlay.displayMode == DM_ThirdPerson))
    {
        if (!conPlay.con.CheckActorDistances(Self))
            conPlay.TerminateConversation(True);
    }
}

// ----------------------------------------------------------------------
// CheckFlagRefs()
//
// Loops through the flagrefs passed in and sees if the current flag
// settings in the game match this set of flags.  Returns True if so,
// otherwise False.
// ----------------------------------------------------------------------

function bool CheckFlagRefs( ConFlagRef flagRef )
{
    local ConFlagRef currentRef;

    // Loop through our list of FlagRef's, checking the value of each.
    // If we hit a bad match, then we'll stop right away since there's
    // no point of continuing.

    currentRef = flagRef;

    while( currentRef != None )
    {
        if ( flagBase.GetBool(currentRef.flagName) != currentRef.value )
            return False;

        currentRef = currentRef.nextFlagRef;
    }
    
    // If we made it this far, then the flags check out.
    return True;
}

// ----------------------------------------------------------------------
// StartDataLinkTransmission()
//
// Locates and starts the DataLink passed in
// ----------------------------------------------------------------------

function Bool StartDataLinkTransmission(
    String datalinkName, 
    Optional DataLinkTrigger datalinkTrigger)
{
    local Conversation activeDataLink;
    local bool bDataLinkPlaySpawned;

    // Don't allow DataLinks to start if we're in PlayersOnly mode
    if ( Level.bPlayersOnly )
        return False;

    activeDataLink = GetActiveDataLink(datalinkName);

    if ( activeDataLink != None )
    {
        // Search to see if there's an active DataLinkPlay object 
        // before creating one

        if ( dataLinkPlay == None )
        {
            datalinkPlay = Spawn(class'DataLinkPlay');
            bDataLinkPlaySpawned = True;
        }

        // Call SetConversation(), which returns 
        if (datalinkPlay.SetConversation(activeDataLink))
        {
            datalinkPlay.SetTrigger(datalinkTrigger);

            if (datalinkPlay.StartConversation(Self))
            {
                return True;
            }
            else
            {
                // Datalink must already be playing, or in queue
                if (bDataLinkPlaySpawned)
                {
                    datalinkPlay.Destroy();
                    datalinkPlay = None;
                }
                
                return False;
            }
        }
        else
        {
            // Datalink must already be playing, or in queue
            if (bDataLinkPlaySpawned)
            {
                datalinkPlay.Destroy();
                datalinkPlay = None;
            }
            return False;
        }
    }
    else
    {
        return False;
    }
}

// ----------------------------------------------------------------------
// GetActiveDataLink()
// 
// Loops through the conversations belonging to the player and checks
// to see if the datalink conversation passed in can be found.  Also
// checks to the "PlayedOnce" flag to prevent datalink transmissions
// from playing more than one (unless intended).
// ----------------------------------------------------------------------

function Conversation GetActiveDataLink(String datalinkName)
{
    local Name flagName;
    local ConListItem conListItem;
    local Conversation con;
    local bool bAbortDataLink;
    local bool bDatalinkFound;
    local bool bDataLinkNameFound;

    // Abort immediately if the flagbase isn't yet initialized
    if ((flagBase == None) || (rootWindow == None))
        return None;

    conListItem = ConListItem(conListItems);

    // In a loop, go through the conversations, checking each.
    while ( conListItem != None )
    {
        con = conListItem.con;

        if ( Caps(datalinkName) == Caps(con.conName) )
        {
            // Now check if this DataLink is only to be played
            // once 

            bDataLinkNameFound = True;
            bAbortDataLink = False;

            if ( con.bDisplayOnce )
            {
                flagName = rootWindow.StringToName(con.conName $ "_Played");        
                bAbortDataLink = (flagBase.GetBool(flagName) == True);
            }

            // Check the flags for this DataLink
            if (( !bAbortDataLink ) && ( CheckFlagRefs( con.flagRefList ) == True ))
            {
                bDatalinkFound = True;
                break;
            }
        }
        conListItem = conListItem.next;
    }

    if (bDatalinkFound)
    {
        return con;
    }
    else
    {
        // Print a warning if this DL couldn't be found based on its name
        if (bDataLinkNameFound == False)
        {
            log("WARNING! INFOLINK NOT FOUND!! Name = " $ datalinkName);
            ClientMessage("WARNING! INFOLINK NOT FOUND!! Name = " $ datalinkName);
        }
        return None;
    }
}

// ----------------------------------------------------------------------
// AddNote()
//
// Adds a new note to the list of notes the player is carrying around.
// ----------------------------------------------------------------------

function DeusExNote AddNote( optional String strNote, optional Bool bUserNote, optional bool bShowInLog )
{
    local DeusExNote newNote;

    newNote = new(Self) Class'DeusExNote';

    newNote.text = strNote;
    newNote.SetUserNote( bUserNote );

    // Insert this new note at the top of the notes list
    if (FirstNote == None)
        LastNote  = newNote;
    else
        newNote.next = FirstNote;

    FirstNote = newNote;

    // Optionally show the note in the log
    if ( bShowInLog )
    {
        ClientMessage(NoteAdded);
        DeusExRootWindow(rootWindow).hud.msgLog.PlayLogSound(Sound'LogNoteAdded');
    }

    return newNote;
}

// ----------------------------------------------------------------------
// GetNote()
//
// Loops through the notes and searches for the TextTag passed in
// ----------------------------------------------------------------------

function DeusExNote GetNote(Name textTag)
{
    local DeusExNote note;

    note = FirstNote;
        
    while( note != None )
    {
        if (note.textTag == textTag)
            break;

        note = note.next;
    }

    return note;
}

// ----------------------------------------------------------------------
// DeleteNote()
//
// Deletes the specified note
// Returns True if the note successfully deleted
// ----------------------------------------------------------------------

function Bool DeleteNote( DeusExNote noteToDelete )
{
    local DeusExNote note;
    local DeusExNote previousNote;
    local Bool bNoteDeleted;

    bNoteDeleted = False;
    note = FirstNote;
    previousNote = None;

    while( note != None )
    {
        if ( note == noteToDelete )
        {
            if ( note == FirstNote )
                FirstNote = note.next;

            if ( note == LastNote )
                LastNote = previousNote;

            if ( previousNote != None )
                previousNote.next = note.next;

            note = None;
                        
            bNoteDeleted = True;    
            break;
        }
        previousNote = note;
        note = note.next;
    }

    return bNoteDeleted;
}

// ----------------------------------------------------------------------
// DeleteAllNotes()
//
// Deletes *ALL* Notes
// ----------------------------------------------------------------------

function DeleteAllNotes()
{
    local DeusExNote note;
    local DeusExNote noteNext;

    note = FirstNote;

    while( note != None )
    {
        noteNext = note.next;
        DeleteNote(note);
        note = noteNext;
    }

    FirstNote = None;
    LastNote = None;
}

// ----------------------------------------------------------------------
// NoteAdd()
// ----------------------------------------------------------------------

exec function NoteAdd( String noteText, optional bool bUserNote )
{
    local DeusExNote newNote;

    newNote = AddNote( noteText );
    newNote.SetUserNote( bUserNote );
}

// ----------------------------------------------------------------------
// AddGoal()
//
// Adds a new goal to the list of goals the player is carrying around.
// ----------------------------------------------------------------------

function DeusExGoal AddGoal( Name goalName, bool bPrimaryGoal )
{   
    local DeusExGoal newGoal;

    // First check to see if this goal already exists.  If so, we'll just
    // return it.  Otherwise create a new goal

    newGoal = FindGoal( goalName );

    if ( newGoal == None )
    {
        newGoal = new(Self) Class'DeusExGoal';
        newGoal.SetName( goalName );

        // Insert goal at the Top so goals are displayed in 
        // Newest order first.
        if (FirstGoal == None)
            LastGoal  = newGoal;
        else
            newGoal.next = FirstGoal;

        FirstGoal    = newGoal;

        newGoal.SetPrimaryGoal( bPrimaryGoal );

        ClientMessage(GoalAdded);
        DeusExRootWindow(rootWindow).hud.msgLog.PlayLogSound(Sound'LogGoalAdded');
    }

    return newGoal; 
}

// ----------------------------------------------------------------------
// FindGoal()
// ----------------------------------------------------------------------

function DeusExGoal FindGoal( Name goalName )
{
    local DeusExGoal goal;

    goal = FirstGoal;

    while( goal != None )
    {
        if ( goalName == goal.goalName )
            break;

        goal = goal.next;
    }

    return goal;
}

// ----------------------------------------------------------------------
// GoalAdd()
//
// Adds a new goal to the list of goals the player is carrying around.
// ----------------------------------------------------------------------

exec function GoalAdd( Name goalName, String goalText, optional bool bPrimaryGoal )
{
    local DeusExGoal newGoal;

    if (!bCheatsEnabled)
        return;

    newGoal = AddGoal( goalName, bPrimaryGoal );
    newGoal.SetText( goalText );
}

// ----------------------------------------------------------------------
// GoalSetPrimary()
//
// Sets a goal as a Primary Goal
// ----------------------------------------------------------------------

exec function GoalSetPrimary( Name goalName, bool bPrimaryGoal )
{
    local DeusExGoal goal;

    if (!bCheatsEnabled)
        return;

    goal = FindGoal( goalName );

    if ( goal != None )
        goal.SetPrimaryGoal( bPrimaryGoal );
}

// ----------------------------------------------------------------------
// GoalCompleted()
//
// Looks up the goal and marks it as completed.
// ----------------------------------------------------------------------

function GoalCompleted( Name goalName )
{
    local DeusExGoal goal;

    // Loop through all the goals until we hit the one we're 
    // looking for.
    goal = FindGoal( goalName );

    if ( goal != None )
    {
        // Only mark a goal as completed once!
        if (!goal.IsCompleted())
        {
            goal.SetCompleted();
            DeusExRootWindow(rootWindow).hud.msgLog.PlayLogSound(Sound'LogGoalCompleted');

            // Let the player know
            if ( goal.bPrimaryGoal )
                ClientMessage(PrimaryGoalCompleted);
            else
                ClientMessage(SecondaryGoalCompleted);
        }
    }
}

// ----------------------------------------------------------------------
// DeleteGoal()
//
// Deletes the specified note
// Returns True if the note successfully deleted
// ----------------------------------------------------------------------

function Bool DeleteGoal( DeusExGoal goalToDelete )
{
    local DeusExGoal goal;
    local DeusExGoal previousGoal;
    local Bool bGoalDeleted;

    bGoalDeleted = False;
    goal = FirstGoal;
    previousGoal = None;

    while( goal != None )
    {
        if ( goal == goalToDelete )
        {
            if ( goal == FirstGoal )
                FirstGoal = goal.next;

            if ( goal == LastGoal )
                LastGoal = previousGoal;

            if ( previousGoal != None )
                previousGoal.next = goal.next;

            goal = None;
                        
            bGoalDeleted = True;    
            break;
        }
        previousGoal = goal;
        goal = goal.next;
    }

    return bGoalDeleted;
}

// ----------------------------------------------------------------------
// DeleteAllGoals()
//
// Deletes *ALL* Goals
// ----------------------------------------------------------------------

function DeleteAllGoals()
{
    local DeusExGoal goal;
    local DeusExGoal goalNext;

    goal = FirstGoal;

    while( goal != None )
    {
        goalNext = goal.next;
        DeleteGoal(goal);
        goal = goalNext;
    }

    FirstGoal = None;
    LastGoal = None;
}

// ----------------------------------------------------------------------
// ResetGoals()
// 
// Called when progressing to the next mission.  Deletes all 
// completed Primary Goals as well as *ALL* Secondary Goals 
// (regardless of status)
// ----------------------------------------------------------------------

function ResetGoals()
{
    local DeusExGoal goal;
    local DeusExGoal goalNext;

    goal = FirstGoal;

    while( goal != None )
    {
        goalNext = goal.next;

        // Delete:
        // 1) Completed Primary Goals
        // 2) ALL Secondary Goals

        if ((!goal.IsPrimaryGoal()) || (goal.IsPrimaryGoal() && goal.IsCompleted()))
            DeleteGoal(goal);

        goal = goalNext;
    }
}

// ----------------------------------------------------------------------
// AddImage()
//
// Inserts a new image in the user's list of images.  First checks to 
// make sure the player doesn't already have the image.  If not, 
// sticks the image at the top of the list.
// ----------------------------------------------------------------------

function bool AddImage(DataVaultImage newImage)
{
    local DataVaultImage image;

    if (newImage == None)
        return False;

    // First make sure the player doesn't already have this image!!
    image = FirstImage;
    while(image != None)
    {
        if (newImage.imageDescription == image.imageDescription)
            return False;

        image = image.NextImage;
    }

    // If the player doesn't yet have an image, make this his
    // first image.  
    newImage.nextImage = FirstImage;
    newImage.prevImage = None;

    if (FirstImage != None)
        FirstImage.prevImage = newImage;

    FirstImage = newImage;

    return True;
}

// ----------------------------------------------------------------------
// AddLog()
//
// Adds a log message to our FirstLog linked list
// ----------------------------------------------------------------------

function DeusExLog AddLog(String logText)
{
    local DeusExLog newLog;

    newLog = CreateLogObject();
    newLog.SetLogText(logText);

    // Add this Note to the list of player Notes
    if ( FirstLog != None )
        LastLog.next = newLog;
    else
        FirstLog = newLog;

    LastLog = newLog;

    return newLog;
}

// ----------------------------------------------------------------------
// ClearLog()
//
// Removes log objects
// ----------------------------------------------------------------------

function ClearLog()
{
    local DeusExLog log;
    local DeusExLog nextLog;

    log = FirstLog;

    while( log != None )
    {
        nextLog = log.next;
        CriticalDelete(log);
        log = nextLog;
    }

    FirstLog = None;
    LastLog  = None;
}

// ----------------------------------------------------------------------
// SetLogTimeout()
// ----------------------------------------------------------------------

function SetLogTimeout(Float newLogTimeout)
{
    logTimeout = newLogTimeout;

    // Update the HUD Log Display
    if (DeusExRootWindow(rootWindow).hud != None)
        DeusExRootWindow(rootWindow).hud.msgLog.SetLogTimeout(newLogTimeout);
}

// ----------------------------------------------------------------------
// GetLogTimeout()
// ----------------------------------------------------------------------

function Float GetLogTimeout()
{
   if (Level.NetMode == NM_Standalone)  
      return logTimeout;
   else
      return (FMax(5.0,logTimeout));
}

// ----------------------------------------------------------------------
// SetMaxLogLines()
// ----------------------------------------------------------------------

function SetMaxLogLines(Byte newLogLines)
{
    maxLogLines = newLogLines;

    // Update the HUD Log Display
    if (DeusExRootWindow(rootWindow).hud != None)
        DeusExRootWindow(rootWindow).hud.msgLog.SetMaxLogLines(newLogLines);
}

// ----------------------------------------------------------------------
// GetMaxLogLines()
// ----------------------------------------------------------------------

function Byte GetMaxLogLines()
{
    return maxLogLines;
}

// ----------------------------------------------------------------------
// PopHealth() - This is used from the health screen (Medkits applied to body parts were not in sync with server)
// ----------------------------------------------------------------------

function PopHealth( float health0, float health1, float health2, float health3, float health4, float health5 )
{
    HealthHead     = health0;
    HealthTorso    = health1;
    HealthArmRight = health2;
    HealthArmLeft  = health3;
    HealthLegRight = health4;
    HealthLegLeft  = health5;
}

// ----------------------------------------------------------------------
// 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 ave, avecrit;

    ave = (HealthLegLeft + HealthLegRight + HealthArmLeft + HealthArmRight) / 4.0;

    if ((HealthHead <= 0) || (HealthTorso <= 0))
        avecrit = 0;
    else
        avecrit = (HealthHead + HealthTorso) / 2.0;

    if (avecrit == 0)
        Health = 0;
    else
        Health = (ave + avecrit) / 2.0;
}


// ----------------------------------------------------------------------
// MultiplayerDeathMsg()
// ----------------------------------------------------------------------
function MultiplayerDeathMsg( Pawn killer, bool killedSelf, bool valid, String killerName, String killerMethod )
{
    local MultiplayerMessageWin mmw;
    local DeusExRootWindow          root;

    myKiller = killer;
    if ( killProfile != None )
    {
        killProfile.bKilledSelf = killedSelf;
        killProfile.bValid = valid;
    }
    root = DeusExRootWindow(rootWindow);
    if ( root != None )
    {
        mmw = MultiplayerMessageWin(root.InvokeUIScreen(Class'MultiplayerMessageWin', True));
        if ( mmw != None )
        {
            mmw.bKilled = true;
            mmw.killerName = killerName;
            mmw.killerMethod = killerMethod;
            mmw.bKilledSelf = killedSelf;
            mmw.bValidMethod = valid;
        }
    }
}

function ShowProgress()
{
    local MultiplayerMessageWin mmw;
    local DeusExRootWindow          root;

    root = DeusExRootWindow(rootWindow);
   if (root != None)
    {
      if (root.GetTopWindow() != None)
         mmw = MultiplayerMessageWin(root.GetTopWindow());

      if ((mmw != None) && (mmw.bDisplayProgress == false))
      {
         mmw.Destroy();
         mmw = None;
      }
      if ( mmw == None )
      {
         mmw = MultiplayerMessageWin(root.InvokeUIScreen(Class'MultiplayerMessageWin', True));
         if ( mmw != None )
         {
            mmw.bKilled = false;
            mmw.bDisplayProgress = true;
            mmw.lockoutTime = Level.TimeSeconds + 0.2;
         }
      }
   }
}     

// ----------------------------------------------------------------------
// ServerConditionalNoitfyMsg
// ----------------------------------------------------------------------

function ServerConditionalNotifyMsg( int code, optional int param, optional string str )
{
    switch( code )
    {
        case MPMSG_FirstPoison:
            if ( (mpMsgServerFlags & MPSERVERFLAG_FirstPoison) == MPSERVERFLAG_FirstPoison )
                return;
            else
                mpMsgServerFlags = mpMsgServerFlags | MPSERVERFLAG_FirstPoison;
            break;
        case MPMSG_FirstBurn:
            if ( (mpMsgServerFlags & MPSERVERFLAG_FirstBurn) == MPSERVERFLAG_FirstBurn )
                return;
            else
                mpMsgServerFlags = mpMsgServerFlags | MPSERVERFLAG_FirstBurn;
            break;
        case MPMSG_TurretInv:
            if ( ( mpMsgServerFlags & MPSERVERFLAG_TurretInv ) == MPSERVERFLAG_TurretInv )
                return;
            else
                mpMsgServerFlags = mpMsgServerFlags | MPSERVERFLAG_TurretInv;
            break;
        case MPMSG_CameraInv:
            if ( ( mpMsgServerFlags & MPSERVERFLAG_CameraInv ) == MPSERVERFLAG_CameraInv )
                return;
            else
                mpMsgServerFlags = mpMsgServerFlags | MPSERVERFLAG_CameraInv;
            break;
        case MPMSG_LostLegs:
            if ( ( mpMsgServerFlags & MPSERVERFLAG_LostLegs) == MPSERVERFLAG_LostLegs )
                return;
            else
                mpMsgServerFlags = mpMsgServerFlags | MPSERVERFLAG_LostLegs;
            break;
        case MPMSG_DropItem:
            if ( ( mpMsgServerFlags & MPSERVERFLAG_DropItem) == MPSERVERFLAG_DropItem )
                return;
            else
                mpMsgServerFlags = mpMsgServerFlags | MPSERVERFLAG_DropItem;
            break;
        case MPMSG_NoCloakWeapon:
            if ( ( mpMsgServerFlags & MPSERVERFLAG_NoCloakWeapon) == MPSERVERFLAG_NoCloakWeapon )
                return;
            else
                mpMsgServerFlags = mpMsgServerFlags | MPSERVERFLAG_NoCloakWeapon;
            break;
    }
    // If we made it here we need to notify
    MultiplayerNotifyMsg( code, param, str );
}

// ----------------------------------------------------------------------
// MultiplayerNotifyMsg()
// ----------------------------------------------------------------------
function MultiplayerNotifyMsg( int code, optional int param, optional string str )
{
    if ( !bHelpMessages )
    {
        switch( code )
        {
            case MPMSG_TeamUnatco:
            case MPMSG_TeamNsf:
            case MPMSG_TeamHit:
            case MPMSG_TeamSpot:
            case MPMSG_FirstPoison:
            case MPMSG_FirstBurn:
            case MPMSG_TurretInv:
            case MPMSG_CameraInv:
            case MPMSG_LostLegs:
            case MPMSG_DropItem:
            case MPMSG_KilledTeammate:
            case MPMSG_TeamLAM:
            case MPMSG_TeamComputer:
            case MPMSG_NoCloakWeapon:
            case MPMSG_TeamHackTurret:
                return;     // Pass on these
            case MPMSG_CloseKills:
            case MPMSG_TimeNearEnd:
                break;      // Go ahead with these
        }
    }

    switch( code )
    {
        case MPMSG_TeamSpot:
            if ( (mpMsgFlags & MPFLAG_FirstSpot) == MPFLAG_FirstSpot )
                return;
            else
                mpMsgFlags = mpMsgFlags | MPFLAG_FirstSpot;
            break;
        case MPMSG_CloseKills:
            if ((param == 0) || (str ~= ""))
            {
                log("Warning: Passed bad params to multiplayer notify msg." );
                return;
            }
            mpMsgOptionalParam = param;
            mpMsgOptionalString = str;
            break;
        case MPMSG_TimeNearEnd:
            if ((param == 0) || (str ~= ""))
            {
                log("Warning: Passed bad params to multiplayer notify msg." );
                return;
            }
            mpMsgOptionalParam = param;
            mpMsgOptionalString = str;      
            break;
        case MPMSG_DropItem:
        case MPMSG_TeamUnatco:
        case MPMSG_TeamNsf:
            if (( DeusExRootWindow(rootWindow) != None ) && ( DeusExRootWindow(rootWindow).hud != None ) && (DeusExRootWindow(rootWindow).hud.augDisplay != None ))
                DeusExRootWindow(rootWindow).hud.augDisplay.RefreshMultiplayerKeys();
            break;
    }
    mpMsgCode = code;
    mpMsgTime = Level.Timeseconds + mpMsgDelay;
    if (( code == MPMSG_TeamUnatco ) || ( code == MPMSG_TeamNsf ))
        mpMsgTime += 2.0;
}


//
// GetSkillInfoFromProjKiller
//
function GetSkillInfoFromProj( DeusExPlayer killer, Actor proj )
{
    local class<Skill> skillClass;

    if ( proj.IsA('GasGrenade') || proj.IsA('LAM') || proj.IsA('EMPGrenade') || proj.IsA('TearGas'))
        skillClass = class'SkillDemolition';
    else if ( proj.IsA('Rocket') || proj.IsA('RocketLAW') || proj.IsA('RocketWP') || proj.IsA('Fireball') || proj.IsA('PlasmaBolt'))
        skillClass = class'SkillWeaponHeavy';
    else if ( proj.IsA('Dart') || proj.IsA('DartFlare') || proj.IsA('DartPoison') || proj.IsA('Shuriken'))
        skillClass = class'SkillWeaponLowTech';
    else if ( proj.IsA('HECannister20mm') )
        skillClass = class'SkillWeaponRifle';
    else if ( proj.IsA('DeusExDecoration') )
    {
        killProfile.activeSkill = NoneString;
        killProfile.activeSkillLevel = 0;
        return;
    }
    if ( killer.SkillSystem != None )
    {
        killProfile.activeSkill = skillClass.Default.skillName;
        killProfile.activeSkillLevel = killer.SkillSystem.GetSkillLevel(skillClass);
    }
}

function GetWeaponName( DeusExWeapon w, out String name )
{
    if ( w != None )
    {
        if ( WeaponGEPGun(w) != None )
            name = WeaponGEPGun(w).shortName;
        else if ( WeaponLAM(w) != None )
            name = WeaponLAM(w).shortName;
        else
            name = w.itemName;
    }
    else
        name = NoneString;
}

//
// CreateKillerProfile
//
function CreateKillerProfile( Pawn killer, int damage, name damageType, String bodyPart )
{
    local DeusExPlayer pkiller;
    local DeusExProjectile proj;
    local DeusExDecoration decProj;
    local Augmentation anAug;
    local int augCnt;
    local DeusExWeapon w;
    local Skill askill;
    local String wShortString;

    if ( killProfile == None )
    {
        log("Warning:"$Self$" has a killProfile that is None!" );
        return;
    }
    else
        killProfile.Reset();

    pkiller = DeusExPlayer(killer);
    
    if ( pkiller != None )
    {
        killProfile.bValid = True;
        killProfile.name = pkiller.PlayerReplicationInfo.PlayerName;
        w = DeusExWeapon(pkiller.inHand);
        GetWeaponName( w, killProfile.activeWeapon );

        // What augs the killer was using
        if ( pkiller.AugmentationSystem != None )
        {
            killProfile.numActiveAugs = pkiller.AugmentationSystem.NumAugsActive();
            augCnt = 0;
            anAug = pkiller.AugmentationSystem.FirstAug;
            while ( anAug != None )
            {
                if ( anAug.bHasIt && anAug.bIsActive && !anAug.bAlwaysActive && (augCnt < ArrayCount(killProfile.activeAugs)))
                {
                    killProfile.activeAugs[augCnt] = anAug.augmentationName;
                    augCnt += 1;
                }
                anAug = anAug.next;
            }
        }
        else
            killProfile.numActiveAugs = 0;

        // My weapon and skill
        GetWeaponName( DeusExWeapon(inHand), killProfile.myActiveWeapon );
        if ( DeusExWeapon(inHand) != None )
        {
            if ( SkillSystem != None )
            {
                askill = SkillSystem.GetSkillFromClass(DeusExWeapon(inHand).GoverningSkill);
                killProfile.myActiveSkill = askill.skillName;
                killProfile.myActiveSkillLevel = askill.CurrentLevel;
            }
        }
        else
        {
            killProfile.myActiveWeapon = NoneString;
            killProfile.myActiveSkill = NoneString;
            killProfile.myActiveSkillLevel = 0;
        }
        // Fill in my own active augs
        if ( AugmentationSystem != None )
        {
            killProfile.myNumActiveAugs = AugmentationSystem.NumAugsActive();
            augCnt = 0;
            anAug = AugmentationSystem.FirstAug;
            while ( anAug != None )
            {
                if ( anAug.bHasIt && anAug.bIsActive && !anAug.bAlwaysActive && (augCnt < ArrayCount(killProfile.myActiveAugs)))
                {
                    killProfile.myActiveAugs[augCnt] = anAug.augmentationName;
                    augCnt += 1;
                }
                anAug = anAug.next;
            }
        }
        killProfile.streak = (pkiller.PlayerReplicationInfo.Streak + 1);
        killProfile.healthLow = pkiller.HealthLegLeft;
        killProfile.healthMid =  pkiller.HealthTorso;
        killProfile.healthHigh = pkiller.HealthHead;
        killProfile.remainingBio = pkiller.Energy;
        killProfile.damage = damage;
        killProfile.bodyLoc = bodyPart;
        killProfile.killerLoc = pkiller.Location;
    }
    else
    {
        killProfile.bValid = False;
        return;
    }

    killProfile.methodStr = NoneString;

    switch( damageType )
    {
        case 'AutoShot':
            killProfile.methodStr = WithTheString $ AutoTurret(myTurretKiller).titleString  $ "!";
            killProfile.bTurretKilled = True;
            killProfile.killerLoc = AutoTurret(myTurretKiller).Location;
            if ( pkiller.SkillSystem != None )
            {
                killProfile.activeSkill = class'SkillComputer'.Default.skillName;
                killProfile.activeSkillLevel = pkiller.SkillSystem.GetSkillLevel(class'SkillComputer');
            }
            break;
        case 'PoisonEffect':
            killProfile.methodStr = PoisonString $ "!";
            killProfile.bPoisonKilled = True;
            killProfile.activeSkill = NoneString;
            killProfile.activeSkillLevel = 0;
            break;
        case 'Burned':
        case 'Flamed':
            if (( WeaponPlasmaRifle(w) != None ) || ( WeaponFlamethrower(w) != None ))
            {
                // Use the weapon if it's still in hand
            }
            else
            {
                killProfile.methodStr = BurnString $ "!";
                killProfile.bBurnKilled = True;
                killProfile.activeSkill = NoneString;
                killProfile.activeSkillLevel = 0;
            }
            break;
    }
    if ( killProfile.methodStr ~= NoneString )
    {
        proj = DeusExProjectile(myProjKiller);
        decProj = DeusExDecoration(myProjKiller);

        if (( killer != None ) && (proj != None) && (!(proj.itemName ~= "")) )
        {
            if ( (LAM(myProjKiller) != None) && (LAM(myProjKiller).bProximityTriggered) )
            {
                killProfile.bProximityKilled = True;
                killProfile.killerLoc = LAM(myProjKiller).Location;
                killProfile.myActiveSkill = class'SkillDemolition'.Default.skillName;
                if ( SkillSystem != None )
                    killProfile.myActiveSkillLevel = SkillSystem.GetSkillLevel(class'SkillDemolition');
                else
                    killProfile.myActiveSkillLevel = 0;
            }
            else
                killProfile.bProjKilled = True;
            killProfile.methodStr = WithString $ proj.itemArticle $ " " $ proj.itemName $ "!";
            GetSkillInfoFromProj( pkiller, myProjKiller );
        }
        else if (( killer != None ) && ( decProj != None ) && (!(decProj.itemName ~= "" )) )
        {
            killProfile.methodStr = WithString $ decProj.itemArticle $ " " $ decProj.itemName $ "!";
            killProfile.bProjKilled = True;
            GetSkillInfoFromProj( pkiller, myProjKiller );
        }
        else if ((killer != None) && (w != None))
        {
            GetWeaponName( w, wShortString );
            killProfile.methodStr = WithString $ w.itemArticle $ " " $ wShortString $ "!";
            askill = pkiller.SkillSystem.GetSkillFromClass(w.GoverningSkill);
            killProfile.activeSkill = askill.skillName;
            killProfile.activeSkillLevel = askill.CurrentLevel;
        }
        else
            log("Warning: Failed to determine killer method killer:"$killer$" damage:"$damage$" damageType:"$damageType$" " );
    }
    // If we still failed dump this to log, and I'll see if there's a condition slipping through...
    if ( killProfile.methodStr ~= NoneString )
    {
        log("===>Warning: Failed to get killer method:"$Self$" damageType:"$damageType$" " );
        killProfile.bValid = False;
    }
}

// ----------------------------------------------------------------------
// TakeDamage()
// ----------------------------------------------------------------------

function TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
{
    local int actualDamage;
    local bool bAlreadyDead, bPlayAnim, bDamageGotReduced;
    local Vector offset, dst;
    local float headOffsetZ, headOffsetY, armOffset;
    local float origHealth, fdst;
    local DeusExLevelInfo info;
    local DeusExWeapon dxw;
    local String bodyString;
    local int MPHitLoc;

    if ( bNintendoImmunity )
        return;

    bodyString = "";
    origHealth = Health;

   if (Level.NetMode != NM_Standalone)
      Damage *= MPDamageMult;

    // 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;

    // add a HUD icon for this damage type
    if ((damageType == 'Poison') || (damageType == 'PoisonEffect'))  // hack
        AddDamageDisplay('PoisonGas', offset);
    else
        AddDamageDisplay(damageType, offset);

    // nanovirus damage doesn't affect us
    if (damageType == 'NanoVirus')
        return;

    // handle poison
    if ((damageType == 'Poison') || ((Level.NetMode != NM_Standalone) && (damageType=='TearGas')) )
    {
        // Notify player if they're getting burned for the first time
        if ( Level.NetMode != NM_Standalone )
            ServerConditionalNotifyMsg( MPMSG_FirstPoison );

        StartPoison( instigatedBy, Damage );
    }

    // reduce our damage correctly
    if (ReducedDamageType == damageType)
        actualDamage = float(actualDamage) * (1.0 - ReducedDamagePct);

    // check for augs or inventory items
    bDamageGotReduced = DXReduceDamage(Damage, damageType, hitLocation, actualDamage, False);

   // DEUS_EX AMSD Multiplayer shield
   if (Level.NetMode != NM_Standalone)
      if (bDamageGotReduced)
      {
         ShieldStatus = SS_Strong;
         ShieldTimer = 1.0;
      }

    if (ReducedDamageType == 'All') //God mode
        actualDamage = 0;

    // Multiplayer only code
    if ( Level.NetMode != NM_Standalone )
    {
        if ( ( instigatedBy != None ) && (instigatedBy.IsA('DeusExPlayer')) )
        {
            // Special case the sniper rifle
            if ((DeusExPlayer(instigatedBy).Weapon != None) && ( DeusExPlayer(instigatedBy).Weapon.class == class'WeaponRifle' ))
            {
                dxw = DeusExWeapon(DeusExPlayer(instigatedBy).Weapon);
                if ( (dxw != None ) && ( !dxw.bZoomed ))
                    actualDamage *= WeaponRifle(dxw).mpNoScopeMult; // Reduce damage if we're not using the scope
            }
            if ( (TeamDMGame(DXGame) != None) && (TeamDMGame(DXGame).ArePlayersAllied(DeusExPlayer(instigatedBy),Self)) )
            {
                // Don't notify if the player hurts themselves
                if ( DeusExPlayer(instigatedBy) != Self )
                {
                    actualDamage *= TeamDMGame(DXGame).fFriendlyFireMult;
                    if (( damageType != 'TearGas' ) && ( damageType != 'PoisonEffect' ))
                        DeusExPlayer(instigatedBy).MultiplayerNotifyMsg( MPMSG_TeamHit );
                }
            }

        }
    }

    // EMP attacks drain BE energy
    if (damageType == 'EMP')
    {
        EnergyDrain += actualDamage;
        EnergyDrainTotal += actualDamage;
        PlayTakeHitSound(actualDamage, damageType, 1);
        return;
    }

    bPlayAnim = True;

    // if we're burning, don't play a hit anim when taking burning damage
    if (damageType == 'Burned')
        bPlayAnim = False;

    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 ); 	// doesn't do anything anyway

    // calculate our hit extents
    headOffsetZ = CollisionHeight * 0.78;
    headOffsetY = CollisionRadius * 0.35;
    armOffset = CollisionRadius * 0.35;

    // We decided to just have 3 hit locations in multiplayer MBCODE
    if (( Level.NetMode == NM_DedicatedServer ) || ( Level.NetMode == NM_ListenServer ))
    {
        MPHitLoc = GetMPHitLocation(HitLocation);

        if (MPHitLoc == 0)
            return;
        else if (MPHitLoc == 1 )
        {
            // MP Headshot is 2x damage
            // narrow the head region
            actualDamage *= 2;
            HealthHead -= actualDamage;
            bodyString = HeadString;
            if (bPlayAnim)
                PlayAnim('HitHead', , 0.1);
        }
        else if ((MPHitLoc == 3) || (MPHitLoc == 4))    // Leg region
        {
            HealthLegRight -= actualDamage;
            HealthLegLeft -= actualDamage;

            if (MPHitLoc == 4)
            {
                if (bPlayAnim)
                    PlayAnim('HitLegRight', , 0.1);
            }
            else if (MPHitLoc == 3)
            {
                if (bPlayAnim)
                    PlayAnim('HitLegLeft', , 0.1);
            }
            // Since the legs are in sync only bleed up damage from one leg (otherwise it's double damage)
            if (HealthLegLeft < 0)
            {
                HealthArmRight += HealthLegLeft;
                HealthTorso += HealthLegLeft;
                HealthArmLeft += HealthLegLeft;
                bodyString = TorsoString;
                HealthLegLeft = 0;
                HealthLegRight = 0;
            }
        }
        else // arms and torso now one region
        {
            HealthArmLeft -= actualDamage;
            HealthTorso -= actualDamage;
            HealthArmRight -= actualDamage;

            bodyString = TorsoString;

            if (MPHitLoc == 6)
            {
                if (bPlayAnim)
                    PlayAnim('HitArmRight', , 0.1);
            }
            else if (MPHitLoc == 5)
            {
                if (bPlayAnim)
                    PlayAnim('HitArmLeft', , 0.1);
            }
            else
            {
                if (bPlayAnim)
                    PlayAnim('HitTorso', , 0.1);
            }
        }
    }
    else // Normal damage code path for single player
    {
        if (offset.z > headOffsetZ)     // head
        {
            // narrow the head region
            if ((Abs(offset.x) < headOffsetY) || (Abs(offset.y) < headOffsetY))
            {
                HealthHead -= actualDamage * 2;
                if (bPlayAnim)
                    PlayAnim('HitHead', , 0.1);
            }
        }
        else if (offset.z < 0.0)    // legs
        {
            if (offset.y > 0.0)
            {
                HealthLegRight -= actualDamage;
                if (bPlayAnim)
                    PlayAnim('HitLegRight', , 0.1);
            }
            else
            {
                HealthLegLeft -= actualDamage;
                if (bPlayAnim)
                    PlayAnim('HitLegLeft', , 0.1);
            }

            // 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;
                if (bPlayAnim)
                    PlayAnim('HitArmRight', , 0.1);
            }
            else if (offset.y < -armOffset)
            {
                HealthArmLeft -= actualDamage;
                if (bPlayAnim)
                    PlayAnim('HitArmLeft', , 0.1);
            }
            else
            {
                HealthTorso -= actualDamage * 2;
                if (bPlayAnim)
                    PlayAnim('HitTorso', , 0.1);
            }

            // if this part is already dead, damage the adjacent part
            if (HealthArmLeft < 0)
            {
                HealthTorso += HealthArmLeft;
                HealthArmLeft = 0;
            }
            if (HealthArmRight < 0)
            {
                HealthTorso += HealthArmRight;
                HealthArmRight = 0;
            }
        }
    }

    // check for a back hit and play the correct anim
    if ((offset.x < 0.0) && bPlayAnim)
    {
        if (offset.z > headOffsetZ)     // head from the back
        {
            // narrow the head region
            if ((Abs(offset.x) < headOffsetY) || (Abs(offset.y) < headOffsetY))
                PlayAnim('HitHeadBack', , 0.1);
        }
        else
            PlayAnim('HitTorsoBack', , 0.1);
    }

    // check for a water hit
    if (Region.Zone.bWaterZone)
    {
        if ((offset.x < 0.0) && bPlayAnim)
            PlayAnim('WaterHitTorsoBack',,0.1);
        else
            PlayAnim('WaterHitTorso',,0.1);
    }

    GenerateTotalHealth();

    if ((damageType != 'Stunned') && (damageType != 'TearGas') && (damageType != 'HalonGas') &&
        (damageType != 'PoisonGas') && (damageType != 'Radiation') && (damageType != 'EMP') &&
        (damageType != 'NanoVirus') && (damageType != 'Drowned') && (damageType != 'KnockedOut'))
        bleedRate += (origHealth-Health)/30.0;  // 30 points of damage = bleed profusely

    if (CarriedDecoration != None)
        DropDecoration();

    // don't let the player die in the training mission
    info = GetLevelInfo();
    if ((info != None) && (info.MissionNumber == 0))
    {
        if (Health <= 0)
        {
            HealthTorso = FMax(HealthTorso, 10);
            HealthHead = FMax(HealthHead, 10);
            GenerateTotalHealth();
        }
    }

    if (Health > 0)
    {
        if ((Level.NetMode != NM_Standalone) && (HealthLegLeft==0) && (HealthLegRight==0))
            ServerConditionalNotifyMsg( MPMSG_LostLegs );

        if (instigatedBy != None)
            damageAttitudeTo(instigatedBy);
        PlayDXTakeDamageHit(actualDamage, hitLocation, damageType, momentum, bDamageGotReduced);
        AISendEvent('Distress', EAITYPE_Visual);
    }
    else
    {
        NextState = '';
        PlayDeathHit(actualDamage, hitLocation, damageType, momentum);
        if ( Level.NetMode != NM_Standalone )
            CreateKillerProfile( instigatedBy, actualDamage, damageType, bodyString );
        if ( actualDamage > mass )
            Health = -1 * actualDamage;
        Enemy = instigatedBy;
        Died(instigatedBy, damageType, HitLocation);
        return;
    }
    MakeNoise(1.0); 

    if ((DamageType == 'Flamed') && !bOnFire)
    {
        // Notify player if they're getting burned for the first time
        if ( Level.NetMode != NM_Standalone )
            ServerConditionalNotifyMsg( MPMSG_FirstBurn );

        CatchFire( instigatedBy );
    }
    myProjKiller = None;
}

// ----------------------------------------------------------------------
// GetMPHitLocation()
// Returns 1 for head, 2 for torso, 3 for left leg, 4 for right leg, 5 for
// left arm, 6 for right arm, 0 for nothing.
// ----------------------------------------------------------------------
simulated function int GetMPHitLocation(Vector HitLocation)
{
    local float HeadOffsetZ;
    local float HeadOffsetY;
    local float ArmOffset;
    local vector Offset;

    offset = (hitLocation - Location) << Rotation;

    // calculate our hit extents
    headOffsetZ = CollisionHeight * 0.78;
    headOffsetY = CollisionRadius * 0.35;
    armOffset = CollisionRadius * 0.35;
    
    if (offset.z > headOffsetZ )
    {
        // narrow the head region
        if ((Abs(offset.x) < headOffsetY) || (Abs(offset.y) < headOffsetY))
        {
            // Headshot, return 1;
            return 1;
        }
        else
        {
            return 0;
        }
    }
    else if (offset.z < 0.0)    // Leg region
    {       
        if (offset.y > 0.0)
        {
            //right leg
            return 4;
        }
        else
        {
            //left leg
            return 3;
        }
    }
    else // arms and torso now one region
    {
        if (offset.y > armOffset)
        {
            return 6;
        }
        else if (offset.y < -armOffset)
        {
            return 5;
        }
        else
        {
            return 2;
        }
    }
    return 0;
}

// ----------------------------------------------------------------------
// DXReduceDamage()
//
// Calculates reduced damage from augmentations and from inventory items
// Also calculates a scalar damage reduction based on the mission number
// ----------------------------------------------------------------------
function bool DXReduceDamage(int Damage, name damageType, vector hitLocation, out int adjustedDamage, bool bCheckOnly)
{
    local float newDamage;
    local float augLevel, skillLevel;
    local float pct;
    local HazMatSuit suit;
    local BallisticArmor armor;
    local bool bReduced;

    bReduced = False;
    newDamage = Float(Damage);

    if ((damageType == 'TearGas') || (damageType == 'PoisonGas') || (damageType == 'Radiation') ||
        (damageType == 'HalonGas')  || (damageType == 'PoisonEffect') || (damageType == 'Poison'))
    {
        if (AugmentationSystem != None)
            augLevel = AugmentationSystem.GetAugLevelValue(class'AugEnviro');

        if (augLevel >= 0.0)
            newDamage *= augLevel;

        // get rid of poison if we're maxed out
        if (newDamage ~= 0.0)
        {
            StopPoison();
            drugEffectTimer -= 4;   // stop the drunk effect
            if (drugEffectTimer < 0)
                drugEffectTimer = 0;
        }

        // go through the actor list looking for owned HazMatSuits
        // since they aren't in the inventory anymore after they are used


      //foreach AllActors(class'HazMatSuit', suit)
//			if ((suit.Owner == Self) && suit.bActive)
      if (UsingChargedPickup(class'HazMatSuit'))
            {
                skillLevel = SkillSystem.GetSkillLevelValue(class'SkillEnviro');
                newDamage *= 0.75 * skillLevel;
            }
    }

    if ((damageType == 'Shot') || (damageType == 'Sabot') || (damageType == 'Exploded') || (damageType == 'AutoShot'))
    {
        // go through the actor list looking for owned BallisticArmor
        // since they aren't in the inventory anymore after they are used
      if (UsingChargedPickup(class'BallisticArmor'))
            {
                skillLevel = SkillSystem.GetSkillLevelValue(class'SkillEnviro');
                newDamage *= 0.5 * skillLevel;
            }
    }

    if (damageType == 'HalonGas')
    {
        if (bOnFire && !bCheckOnly)
            ExtinguishFire();
    }

    if ((damageType == 'Shot') || (damageType == 'AutoShot'))
    {
        if (AugmentationSystem != None)
            augLevel = AugmentationSystem.GetAugLevelValue(class'AugBallistic');

        if (augLevel >= 0.0)
            newDamage *= augLevel;
    }

    if (damageType == 'EMP')
    {
        if (AugmentationSystem != None)
            augLevel = AugmentationSystem.GetAugLevelValue(class'AugEMP');

        if (augLevel >= 0.0)
            newDamage *= augLevel;
    }

    if ((damageType == 'Burned') || (damageType == 'Flamed') ||
        (damageType == 'Exploded') || (damageType == 'Shocked'))
    {
        if (AugmentationSystem != None)
            augLevel = AugmentationSystem.GetAugLevelValue(class'AugShield');

        if (augLevel >= 0.0)
            newDamage *= augLevel;
    }

    if (newDamage < Damage)
    {
        if (!bCheckOnly)
        {
            pct = 1.0 - (newDamage / Float(Damage));
            SetDamagePercent(pct);
            ClientFlash(0.01, vect(0, 0, 50));
        }
        bReduced = True;
    }
    else
    {
        if (!bCheckOnly)
            SetDamagePercent(0.0);
    }


    //
    // Reduce or increase the damage based on the combat difficulty setting
    //
    if ((damageType == 'Shot') || (damageType == 'AutoShot'))
    {
        newDamage *= CombatDifficulty;

        // always take at least one point of damage
        if ((newDamage <= 1) && (Damage > 0))
            newDamage = 1;
    }

    adjustedDamage = Int(newDamage);

    return bReduced;
}

// ----------------------------------------------------------------------
// Died()
//
// Checks to see if a conversation is playing when the PC dies.
// If so, nukes it.
// ----------------------------------------------------------------------

function Died(pawn Killer, name damageType, vector HitLocation)
{
    if (conPlay != None)
        conPlay.TerminateConversation();

    if (bOnFire)
        ExtinguishFire();

    if (AugmentationSystem != None)
        AugmentationSystem.DeactivateAll();

   if ((Level.NetMode == NM_DedicatedServer) || (Level.NetMode == NM_ListenServer))
      ClientDeath();

    Super.Died(Killer, damageType, HitLocation);
}

// ----------------------------------------------------------------------
// ClientDeath()
// 
// Does client side cleanup on death.
// ----------------------------------------------------------------------

function ClientDeath()
{   
   if (!PlayerIsClient())
      return;

   FlashTimer = 0;

    // Reset skill notification
    DeusExRootWindow(rootWindow).hud.hms.bNotifySkills = False;

   DeusExRootWindow(rootWindow).hud.activeItems.winItemsContainer.RemoveAllIcons();
   DeusExRootWindow(rootWindow).hud.belt.ClearBelt();

    // This should get rid of the scope death problem in multiplayer
    if (( DeusExRootWindow(rootWindow).scopeView != None ) && DeusExRootWindow(rootWindow).scopeView.bViewVisible )
       DeusExRootWindow(rootWindow).scopeView.DeactivateView();

    if ( DeusExRootWindow(rootWindow).hud.augDisplay != None )
    {
        DeusExRootWindow(rootWindow).hud.augDisplay.bVisionActive = False;
        DeusExRootWindow(rootWindow).hud.augDisplay.activeCount = 0;
    }

    if ( bOnFire )
        ExtinguishFire();

    // Don't come back to life drugged or posioned
    poisonCounter       = 0;
    poisonTimer         = 0;
    drugEffectTimer = 0;

    // Don't come back to life crouched
    bCrouchOn           = False;
    bWasCrouchOn        = False;
    bIsCrouching        = False;
    bForceDuck          = False;
    lastbDuck           = 0;
    bDuck                   = 0;

    // No messages carry over
    mpMsgCode = 0;
    mpMsgTime = 0;

   bleedrate = 0;
   dropCounter = 0;

}

// ----------------------------------------------------------------------
// Timer()
//
// continually burn and do damage
// ----------------------------------------------------------------------

function Timer()
{
    local int damage;

    if (!InConversation() && bOnFire)
    {
        if ( Level.NetMode != NM_Standalone )
            damage = Class'WeaponFlamethrower'.Default.mpBurnDamage;
        else
            damage = Class'WeaponFlamethrower'.Default.BurnDamage;
        TakeDamage(damage, myBurner, Location, vect(0,0,0), 'Burned');

        if (HealthTorso <= 0)
        {
            TakeDamage(10, myBurner, Location, vect(0,0,0), 'Burned');
            ExtinguishFire();
        }
    }
}

// ----------------------------------------------------------------------
// CatchFire()
// ----------------------------------------------------------------------

function CatchFire( Pawn burner )
{
    local Fire f;
    local int i;
    local vector loc;

    myBurner = burner;

    burnTimer = 0;

   if (bOnFire || Region.Zone.bWaterZone)
        return;

    bOnFire = True;
    burnTimer = 0;

    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;

      // DEUS_EX AMSD reduce the number of smoke particles in multiplayer
      // by creating smokeless fire (better for server propagation).
      if ((Level.NetMode == NM_Standalone) || (i <= 0))     
         f = Spawn(class'Fire', Self,, loc);
      else
         f = Spawn(class'SmokelessFire', Self,, loc);

        if (f != None)
        {
            f.DrawScale = 0.5*FRand() + 1.0;

         //DEUS_EX AMSD Reduce the penalty in multiplayer
         if (Level.NetMode != NM_Standalone)
            f.DrawScale = f.DrawScale * 0.5;

            // 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
         // MP already only generates a little.
            if ((FRand() < 0.5) && (Level.NetMode == NM_Standalone))
                f.smokeGen.Destroy();
            if ((FRand() < 0.5) && (Level.NetMode == NM_Standalone))
                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();
}

// ----------------------------------------------------------------------
// SpawnBlood()
// ----------------------------------------------------------------------

function SpawnBlood(Vector HitLocation, float Damage)
{
    local int i;

   if ((DeusExMPGame(Level.Game) != None) && (!DeusExMPGame(Level.Game).bSpawnEffects))
   {
      return;
   }

    spawn(class'BloodSpurt',,,HitLocation);
    spawn(class'BloodDrop',,,HitLocation);
    for (i=0; i<int(Damage); i+=10)
        spawn(class'BloodDrop',,,HitLocation);
}

// ----------------------------------------------------------------------
// PlayDXTakeDamageHit()
// DEUS_EX AMSD Created as a separate function to avoid extra calls to
// DXReduceDamage, which is slow in multiplayer
// ----------------------------------------------------------------------
function PlayDXTakeDamageHit(float Damage, vector HitLocation, name damageType, vector Momentum, bool DamageReduced)
{
    local float rnd;

   PlayHit(Damage,HitLocation,damageType,Momentum);

    // if we actually took the full damage, flash the screen and play the sound
   // DEUS_EX AMSD DXReduceDamage is slow.  Pass in the result from earlier.
    if (!DamageReduced) 
    {
        if ( (damage > 0) || (ReducedDamageType == 'All') )
        {
            // No client flash on plasma bolts in multiplayer
            if (( Level.NetMode != NM_Standalone ) && ( myProjKiller != None ) && (PlasmaBolt(myProjKiller)!=None) )
            {
            }
            else
            {
                rnd = FClamp(Damage, 20, 100);
                if (damageType == 'Burned')
                    ClientFlash(rnd * 0.002, vect(200,100,100));
                else if (damageType == 'Flamed')
                    ClientFlash(rnd * 0.002, vect(200,100,100));
                else if (damageType == 'Radiation')
                    ClientFlash(rnd * 0.002, vect(100,100,0));
                else if (damageType == 'PoisonGas')
                    ClientFlash(rnd * 0.002, vect(50,150,0));
                else if (damageType == 'TearGas')
                    ClientFlash(rnd * 0.002, vect(150,150,0));
                else if (damageType == 'Drowned')
                    ClientFlash(rnd * 0.002, vect(0,100,200));
                else if (damageType == 'EMP')
                    ClientFlash(rnd * 0.002, vect(0,200,200));
                else 
                    ClientFlash(rnd * 0.002, vect(50,0,0));
            }
            ShakeView(0.15 + 0.002 * Damage, Damage * 30, 0.3 * Damage); 
        }
    }
}

// ----------------------------------------------------------------------
// PlayHit()
// ----------------------------------------------------------------------

function PlayHit(float Damage, vector HitLocation, name damageType, vector Momentum)
{
    if ((Damage > 0) && (damageType == 'Shot') || (damageType == 'Exploded') || (damageType == 'AutoShot'))
        SpawnBlood(HitLocation, Damage);

    PlayTakeHitSound(Damage, damageType, 1);
}

// ----------------------------------------------------------------------
// PlayDeathHit()
// ----------------------------------------------------------------------

function PlayDeathHit(float Damage, vector HitLocation, name damageType, vector Momentum)
{
    PlayDying(damageType, HitLocation);
}

// ----------------------------------------------------------------------
// SkillPointsAdd()
// ----------------------------------------------------------------------

function SkillPointsAdd(int numPoints)
{
    if (numPoints > 0)
    {
        SkillPointsAvail += numPoints;
        SkillPointsTotal += numPoints;

        if ((DeusExRootWindow(rootWindow) != None) &&
            (DeusExRootWindow(rootWindow).hud != None) && 
            (DeusExRootWindow(rootWindow).hud.msgLog != None))
        {
            ClientMessage(Sprintf(SkillPointsAward, numPoints));
            DeusExRootWindow(rootWindow).hud.msgLog.PlayLogSound(Sound'LogSkillPoints');
        }
    }
}

// ----------------------------------------------------------------------
// MakePlayerIgnored()
// ----------------------------------------------------------------------

function MakePlayerIgnored(bool bNewIgnore)
{
    bIgnore = bNewIgnore;
    // to restore original behavior, uncomment the next line
    //bDetectable = !bNewIgnore;
}

// ----------------------------------------------------------------------
// CalculatePlayerVisibility()
// ----------------------------------------------------------------------

function float CalculatePlayerVisibility(ScriptedPawn P)
{
    local float vis;
    local AdaptiveArmor armor;

    vis = 1.0;
    if ((P != None) && (AugmentationSystem != None))
    {
        if (P.IsA('Robot'))
        {
            // if the aug is on, give the player full invisibility
            if (AugmentationSystem.GetAugLevelValue(class'AugRadarTrans') != -1.0)
                vis = 0.0;
        }
        else
        {
            // if the aug is on, give the player full invisibility
            if (AugmentationSystem.GetAugLevelValue(class'AugCloak') != -1.0)
                vis = 0.0;
        }

        // go through the actor list looking for owned AdaptiveArmor
        // since they aren't in the inventory anymore after they are used

      if (UsingChargedPickup(class'AdaptiveArmor'))
            {
                vis = 0.0;
            }
    }

    return vis;
}

// ----------------------------------------------------------------------
// ClientFlash()
//
// copied from Engine.PlayerPawn
// modified to add the new flash to the current flash
// ----------------------------------------------------------------------
// MBCODE: changed to simulated so that player can experience flash client side
// DEUS_EX AMSD: Added so we can change the flash time duration.
simulated function ClientFlash( float scale, vector fog)
{
    DesiredFlashScale += scale;
    DesiredFlashFog += 0.001 * fog;
}

function IncreaseClientFlashLength(float NewFlashTime)
{
   FlashTimer = FMax(NewFlashTime,FlashTimer);
}

// ----------------------------------------------------------------------
// ViewFlash()
// modified so that flash doesn't always go away in exactly half a second.
// ---------------------------------------------------------------------
function ViewFlash(float DeltaTime)
{
    local float delta;
    local vector goalFog;
    local float goalscale, ReductionFactor;

   ReductionFactor = 2;

   if (FlashTimer > 0)
   {
      if (FlashTimer < Deltatime)
      {
         FlashTimer = 0;
      }
      else
      {
         ReductionFactor = 0;
         FlashTimer -= Deltatime;
      }
   }

   if ( bNoFlash )
    {
        InstantFlash = 0;
        InstantFog = vect(0,0,0);
    }

    delta = FMin(0.1, DeltaTime);
    goalScale = 1 + DesiredFlashScale + ConstantGlowScale + HeadRegion.Zone.ViewFlash.X; 
    goalFog = DesiredFlashFog + ConstantGlowFog + HeadRegion.Zone.ViewFog;
    DesiredFlashScale -= DesiredFlashScale * ReductionFactor * delta;  
    DesiredFlashFog -= DesiredFlashFog * ReductionFactor * delta;
    FlashScale.X += (goalScale - FlashScale.X + InstantFlash) * 10 * delta;
    FlashFog += (goalFog - FlashFog + InstantFog) * 10 * delta;
    InstantFlash = 0;
    InstantFog = vect(0,0,0);

    if ( FlashScale.X > 0.981 )
        FlashScale.X = 1;
    FlashScale = FlashScale.X * vect(1,1,1);

    if ( FlashFog.X < 0.019 )
        FlashFog.X = 0;
    if ( FlashFog.Y < 0.019 )
        FlashFog.Y = 0;
    if ( FlashFog.Z < 0.019 )
        FlashFog.Z = 0;
}
// ----------------------------------------------------------------------
// ViewModelAdd()
//
// lets an artist (or whoever) view a model and play animations on it
// from within the game
// ----------------------------------------------------------------------

exec function ViewModelAdd(int num, string ClassName)
{
    local class<actor> ViewModelClass;
    local rotator newrot;
    local vector loc;

    if (!bCheatsEnabled)
        return;

    if(instr(ClassName, ".") == -1)
        ClassName = "DeusEx." $ ClassName;

    if ((num >= 0) && (num <= 8))
    {
        if (num > 0)
            num--;

        if (ViewModelActor[num] == None)
        {
            ViewModelClass = class<actor>(DynamicLoadObject(ClassName, class'Class'));
            if (ViewModelClass != None)
            {
                newrot = Rotation;
                newrot.Roll = 0;
                newrot.Pitch = 0;
                loc = Location + (ViewModelClass.Default.CollisionRadius + CollisionRadius + 32) * Vector(newrot);
                loc.Z += ViewModelClass.Default.CollisionHeight;
                ViewModelActor[num] = Spawn(ViewModelClass,,, loc, newrot);
                if (ViewModelActor[num] != None)
                    ViewModelActor[num].SetPhysics(PHYS_None);
                if (ScriptedPawn(ViewModelActor[num]) != None)
                    ViewModelActor[num].GotoState('Paralyzed');
            }
        }
        else
            ClientMessage("There is already a ViewModel in that slot!");
    }
}

// ----------------------------------------------------------------------
// ViewModelDestroy()
//
// destroys the current ViewModel
// ----------------------------------------------------------------------

exec function ViewModelDestroy(int num)
{
    local int i;

    if (!bCheatsEnabled)
        return;

    if ((num >= 0) && (num <= 8))
    {
        if (num == 0)
        {
            for (i=0; i<8; i++)
                if (ViewModelActor[i] != None)
                {
                    ViewModelActor[i].Destroy();
                    ViewModelActor[i] = None;
                }
        }
        else
        {
            i = num - 1;
            if (ViewModelActor[i] != None)
            {
                ViewModelActor[i].Destroy();
                ViewModelActor[i] = None;
            }
        }
    }
}

// ----------------------------------------------------------------------
// ViewModelPlay()
//
// plays an animation on the current ViewModel
// ----------------------------------------------------------------------

exec function ViewModelPlay(int num, name anim, optional float fps)
{
    local int i;

    if (!bCheatsEnabled)
        return;

    if ((num >= 0) && (num <= 8))
    {
        if (num == 0)
        {
            for (i=0; i<8; i++)
                if (ViewModelActor[i] != None)
                {
                    if (fps == 0)
                        fps = 1.0;
                    ViewModelActor[i].PlayAnim(anim, fps);
                }
        }
        else
        {
            i = num - 1;
            if (ViewModelActor[i] != None)
            {
                if (fps == 0)
                    fps = 1.0;
                ViewModelActor[i].PlayAnim(anim, fps);
            }
        }
    }
}

// ----------------------------------------------------------------------
// ViewModelLoop()
//
// loops an animation on the current ViewModel
// ----------------------------------------------------------------------

exec function ViewModelLoop(int num, name anim, optional float fps)
{
    local int i;

    if (!bCheatsEnabled)
        return;

    if ((num >= 0) && (num <= 8))
    {
        if (num == 0)
        {
            for (i=0; i<8; i++)
                if (ViewModelActor[i] != None)
                {
                    if (fps == 0)
                        fps = 1.0;
                    ViewModelActor[i].LoopAnim(anim, fps);
                }
        }
        else
        {
            i = num - 1;
            if (ViewModelActor[i] != None)
            {
                if (fps == 0)
                    fps = 1.0;
                ViewModelActor[i].LoopAnim(anim, fps);
            }
        }
    }
}

// ----------------------------------------------------------------------
// ViewModelBlendPlay()
//
// plays a blended animation on the current ViewModel
// ----------------------------------------------------------------------

exec function ViewModelBlendPlay(int num, name anim, optional float fps, optional int slot)
{
    local int i;

    if (!bCheatsEnabled)
        return;

    if ((num >= 0) && (num <= 8))
    {
        if (num == 0)
        {
            for (i=0; i<8; i++)
                if (ViewModelActor[i] != None)
                {
                    if (fps == 0)
                        fps = 1.0;
                    ViewModelActor[i].PlayBlendAnim(anim, fps, , slot);
                }
        }
        else
        {
            i = num - 1;
            if (ViewModelActor[i] != None)
            {
                if (fps == 0)
                    fps = 1.0;
                ViewModelActor[i].PlayBlendAnim(anim, fps, , slot);
            }
        }
    }
}

// ----------------------------------------------------------------------
// ViewModelBlendStop()
//
// stops the blended animation on the current ViewModel
// ----------------------------------------------------------------------

exec function ViewModelBlendStop(int num)
{
    local int i;

    if (!bCheatsEnabled)
        return;

    if ((num >= 0) && (num <= 8))
    {
        if (num == 0)
        {
            for (i=0; i<8; i++)
                if (ViewModelActor[i] != None)
                    ViewModelActor[i].StopBlendAnims();
        }
        else
        {
            i = num - 1;
            if (ViewModelActor[i] != None)
                ViewModelActor[i].StopBlendAnims();
        }
    }
}

exec function ViewModelGiveWeapon(int num, string weaponClass)
{
    local class<Actor> NewClass;
    local Actor obj;
    local int i;
    local ScriptedPawn pawn;

    if (!bCheatsEnabled)
        return;

    if (instr(weaponClass, ".") == -1)
        weaponClass = "DeusEx." $ weaponClass;

    if ((num >= 0) && (num <= 8))
    {
        NewClass = class<Actor>(DynamicLoadObject(weaponClass, class'Class'));

        if (NewClass != None)
        {
            obj = Spawn(NewClass,,, Location + (CollisionRadius+NewClass.Default.CollisionRadius+30) * Vector(Rotation) + vect(0,0,1) * 15);
            if ((obj != None) && obj.IsA('DeusExWeapon'))
            {
                if (num == 0)
                {
                    for (i=0; i<8; i++)
                    {
                        pawn = ScriptedPawn(ViewModelActor[i]);
                        if (pawn != None)
                        {
                            DeusExWeapon(obj).GiveTo(pawn);
                            obj.SetBase(pawn);
                            pawn.Weapon = DeusExWeapon(obj);
                            pawn.PendingWeapon = DeusExWeapon(obj);
                        }
                    }
                }
                else
                {
                    i = num - 1;
                    pawn = ScriptedPawn(ViewModelActor[i]);
                    if (pawn != None)
                    {
                        DeusExWeapon(obj).GiveTo(pawn);
                        obj.SetBase(pawn);
                        pawn.Weapon = DeusExWeapon(obj);
                        pawn.PendingWeapon = DeusExWeapon(obj);
                    }
                }
            }
            else
            {
                if (obj != None)
                    obj.Destroy();
            }
        }
    }
}

// ----------------------------------------------------------------------
// aliases to ViewModel functions
// ----------------------------------------------------------------------

exec function VMA(int num, string ClassName)
{
    ViewModelAdd(num, ClassName);
}

exec function VMD(int num)
{
    ViewModelDestroy(num);
}

exec function VMP(int num, name anim, optional float fps)
{
    ViewModelPlay(num, anim, fps);
}

exec function VML(int num, name anim, optional float fps)
{
    ViewModelLoop(num, anim, fps);
}

exec function VMBP(int num, name anim, optional float fps, optional int slot)
{
    ViewModelBlendPlay(num, anim, fps, slot);
}

exec function VMBS(int num)
{
    ViewModelBlendStop(num);
}

exec function VMGW(int num, string weaponClass)
{
    ViewModelGiveWeapon(num, weaponClass);
}

// ----------------------------------------------------------------------
// Cheat functions
//
// ----------------------------------------------------------------------
// AllHealth()
// ----------------------------------------------------------------------

exec function AllHealth()
{
    if (!bCheatsEnabled)
        return;

    RestoreAllHealth();
}

// ----------------------------------------------------------------------
// RestoreAllHealth()
// ----------------------------------------------------------------------

function RestoreAllHealth()
{
    HealthHead = default.HealthHead;
    HealthTorso = default.HealthTorso;
    HealthLegLeft = default.HealthLegLeft;
    HealthLegRight = default.HealthLegRight;
    HealthArmLeft = default.HealthArmLeft;
    HealthArmRight = default.HealthArmRight;
    Health = default.Health;
}

// ----------------------------------------------------------------------
// DamagePart()
// ----------------------------------------------------------------------

exec function DamagePart(int partIndex, optional int amount)
{
    if (!bCheatsEnabled)
        return;

    if (amount == 0)
        amount = 1000;

    switch(partIndex)
    {
        case 0:     // head
            HealthHead -= Min(HealthHead, amount);
            break;

        case 1:     // torso
            HealthTorso -= Min(HealthTorso, amount);
            break;

        case 2:     // left arm
            HealthArmLeft -= Min(HealthArmLeft, amount);
            break;

        case 3:     // right arm
            HealthArmRight -= Min(HealthArmRight, amount);
            break;

        case 4:     // left leg
            HealthLegLeft -= Min(HealthLegLeft, amount);
            break;

        case 5:     // right leg
            HealthLegRight -= Min(HealthLegRight, amount);
            break;
    }
}

// ----------------------------------------------------------------------
// DamageAll()
// ----------------------------------------------------------------------

exec function DamageAll(optional int amount)
{
    if (!bCheatsEnabled)
        return;

    if (amount == 0)
        amount = 1000;

    HealthHead     -= Min(HealthHead, amount);
    HealthTorso    -= Min(HealthTorso, amount);
    HealthArmLeft  -= Min(HealthArmLeft, amount);
    HealthArmRight -= Min(HealthArmRight, amount);
    HealthLegLeft  -= Min(HealthLegLeft, amount);
    HealthLegRight -= Min(HealthLegRight, amount);
}

// ----------------------------------------------------------------------
// AllEnergy()
// ----------------------------------------------------------------------

exec function AllEnergy()
{
    if (!bCheatsEnabled)
        return;

    Energy = default.Energy;
}

// ----------------------------------------------------------------------
// AllCredits()
// ----------------------------------------------------------------------

exec function AllCredits()
{
    if (!bCheatsEnabled)
        return;

    Credits = 100000;
}

// ---------------------------------------------------------------------
// AllSkills()
// ----------------------------------------------------------------------

exec function AllSkills()
{
    if (!bCheatsEnabled)
        return;

    AllSkillPoints();
    SkillSystem.AddAllSkills();
}

// ----------------------------------------------------------------------
// AllSkillPoints()
// ----------------------------------------------------------------------

exec function AllSkillPoints()
{
    if (!bCheatsEnabled)
        return;

    SkillPointsTotal = 115900;
    SkillPointsAvail = 115900;
}

// ----------------------------------------------------------------------
// AllAugs()
// ----------------------------------------------------------------------

exec function AllAugs()
{
    local Augmentation anAug;
    local int i;
    
    if (!bCheatsEnabled)
        return;

    if (AugmentationSystem != None)
    {
        AugmentationSystem.AddAllAugs();
        AugmentationSystem.SetAllAugsToMaxLevel();
    }
}

// ----------------------------------------------------------------------
// AllWeapons()
// ----------------------------------------------------------------------

exec function AllWeapons()
{
    local Vector loc;

    if (!bCheatsEnabled)
        return;

    loc = Location + 2 * CollisionRadius * Vector(ViewRotation);

    Spawn(class'WeaponAssaultGun',,, loc);
    Spawn(class'WeaponAssaultShotgun',,, loc);
    Spawn(class'WeaponBaton',,, loc);
    Spawn(class'WeaponCombatKnife',,, loc);
    Spawn(class'WeaponCrowbar',,, loc);
    Spawn(class'WeaponEMPGrenade',,, loc);
    Spawn(class'WeaponFlamethrower',,, loc);
    Spawn(class'WeaponGasGrenade',,, loc);
    Spawn(class'WeaponGEPGun',,, loc);
    Spawn(class'WeaponHideAGun',,, loc);
    Spawn(class'WeaponLAM',,, loc);
    Spawn(class'WeaponLAW',,, loc);
    Spawn(class'WeaponMiniCrossbow',,, loc);
    Spawn(class'WeaponNanoSword',,, loc);
    Spawn(class'WeaponNanoVirusGrenade',,, loc);
    Spawn(class'WeaponPepperGun',,, loc);
    Spawn(class'WeaponPistol',,, loc);
    Spawn(class'WeaponPlasmaRifle',,, loc);
    Spawn(class'WeaponProd',,, loc);
    Spawn(class'WeaponRifle',,, loc);
    Spawn(class'WeaponSawedOffShotgun',,, loc);
    Spawn(class'WeaponShuriken',,, loc);
    Spawn(class'WeaponStealthPistol',,, loc);
    Spawn(class'WeaponSword',,, loc);
}

// ----------------------------------------------------------------------
// AllImages()
// ----------------------------------------------------------------------

exec function AllImages()
{
    local Vector loc;
    local Inventory item;

    if (!bCheatsEnabled)
        return;

    item = Spawn(class'Image01_GunFireSensor');
    item.Frob(Self, None);
    item = Spawn(class'Image01_LibertyIsland');
    item.Frob(Self, None);
    item = Spawn(class'Image01_TerroristCommander');
    item.Frob(Self, None);
    item = Spawn(class'Image02_Ambrosia_Flyer');
    item.Frob(Self, None);
    item = Spawn(class'Image02_NYC_Warehouse');
    item.Frob(Self, None);
    item = Spawn(class'Image02_BobPage_ManOfYear');
    item.Frob(Self, None);
    item = Spawn(class'Image03_747Diagram');
    item.Frob(Self, None);
    item = Spawn(class'Image03_NYC_Airfield');
    item.Frob(Self, None);
    item = Spawn(class'Image03_WaltonSimons');
    item.Frob(Self, None);
    item = Spawn(class'Image04_NSFHeadquarters');
    item.Frob(Self, None);
    item = Spawn(class'Image04_UNATCONotice');
    item.Frob(Self, None);
    item = Spawn(class'Image05_GreaselDisection');
    item.Frob(Self, None);
    item = Spawn(class'Image05_NYC_MJ12Lab');
    item.Frob(Self, None);
    item = Spawn(class'Image06_HK_Market');
    item.Frob(Self, None);
    item = Spawn(class'Image06_HK_MJ12Helipad');
    item.Frob(Self, None);
    item = Spawn(class'Image06_HK_MJ12Lab');
    item.Frob(Self, None);
    item = Spawn(class'Image06_HK_Versalife');
    item.Frob(Self, None);
    item = Spawn(class'Image06_HK_WanChai');
    item.Frob(Self, None);
    item = Spawn(class'Image08_JoeGreenMIBMJ12');
    item.Frob(Self, None);
    item = Spawn(class'Image09_NYC_Ship_Bottom');
    item.Frob(Self, None);
    item = Spawn(class'Image09_NYC_Ship_Top');
    item.Frob(Self, None);
    item = Spawn(class'Image10_Paris_Catacombs');
    item.Frob(Self, None);
    item = Spawn(class'Image10_Paris_CatacombsTunnels');
    item.Frob(Self, None);
    item = Spawn(class'Image10_Paris_Metro');
    item.Frob(Self, None);
    item = Spawn(class'Image11_Paris_Cathedral');
    item.Frob(Self, None);
    item = Spawn(class'Image11_Paris_CathedralEntrance');
    item.Frob(Self, None);
    item = Spawn(class'Image12_Vandenberg_Command');
    item.Frob(Self, None);
    item = Spawn(class'Image12_Vandenberg_Sub');
    item.Frob(Self, None);
    item = Spawn(class'Image12_Tiffany_HostagePic');
    item.Frob(Self, None);
    item = Spawn(class'Image14_OceanLab');
    item.Frob(Self, None);
    item = Spawn(class'Image14_Schematic');
    item.Frob(Self, None);
    item = Spawn(class'Image15_Area51Bunker');
    item.Frob(Self, None);
    item = Spawn(class'Image15_GrayDisection');
    item.Frob(Self, None);
    item = Spawn(class'Image15_BlueFusionDevice');
    item.Frob(Self, None);
    item = Spawn(class'Image15_Area51_Sector3');
    item.Frob(Self, None);
    item = Spawn(class'Image15_Area51_Sector4');
    item.Frob(Self, None);
}

// ----------------------------------------------------------------------
// Trig()
// ----------------------------------------------------------------------

exec function Trig(name ev)
{
    local Actor A;

    if (!bCheatsEnabled)
        return;

    if (ev != '')
        foreach AllActors(class'Actor', A, ev)
            A.Trigger(Self, Self);
}

// ----------------------------------------------------------------------
// UnTrig()
// ----------------------------------------------------------------------

exec function UnTrig(name ev)
{
    local Actor A;

    if (!bCheatsEnabled)
        return;

    if (ev != '')
        foreach AllActors(class'Actor', A, ev)
            A.UnTrigger(Self, Self);
}

// ----------------------------------------------------------------------
// SetState()
// ----------------------------------------------------------------------

exec function SetState(name state)
{
    local ScriptedPawn P;
    local Actor hitActor;
    local vector loc, line, HitLocation, hitNormal;

    if (!bCheatsEnabled)
        return;

    loc = Location;
    loc.Z += BaseEyeHeight;
    line = Vector(ViewRotation) * 2000;

    hitActor = Trace(hitLocation, hitNormal, loc+line, loc, true);
    P = ScriptedPawn(hitActor);
    if (P != None)
    {
        P.GotoState(state);
        ClientMessage("Setting "$P.BindName$" to the "$state$" state");
    }
}

// ----------------------------------------------------------------------
// DXDumpInfo()
//
// Dumps the following player information to the log file
// - inventory (with item counts)
// - health (as %)
// - energy (as %)
// - credits
// - skill points (avail and max)
// - skills
// - augmentations
// ----------------------------------------------------------------------

exec function DXDumpInfo()
{
    local DumpLocation dumploc;
    local DeusExLevelInfo info;
    local string userName, mapName, strCopies;
    local Inventory item, nextItem;
    local DeusExWeapon W;
    local Skill skill;
    local Augmentation aug;
    local bool bHasAugs;

    dumploc = CreateDumpLocationObject();
    if (dumploc != None)
    {
        userName = dumploc.GetCurrentUser();
        CriticalDelete(dumploc);
    }

    if (userName == "")
        userName = "NO USERNAME";

    mapName = "NO MAPNAME";
    foreach AllActors(class'DeusExLevelInfo', info)
        mapName = info.MapName;

    log("");
    log("**** DXDumpInfo - User: "$userName$" - Map: "$mapName$" ****");
    log("");
    log("  Inventory:");

    if (Inventory != None)
    {
        item = Inventory;
        do
        {
            nextItem = item.Inventory;

            if (item.bDisplayableInv || item.IsA('Ammo'))
            {
                W = DeusExWeapon(item);
                if ((W != None) && W.bHandToHand && (W.ProjectileClass != None))
                    strCopies = " ("$W.AmmoType.AmmoAmount$" rds)";
                else if (item.IsA('Ammo') && (Ammo(item).PickupViewMesh != Mesh'TestBox'))
                    strCopies = " ("$Ammo(item).AmmoAmount$" rds)";
                else if (item.IsA('Pickup') && (Pickup(item).NumCopies > 1))
                    strCopies = " ("$Pickup(item).NumCopies$")";
                else
                    strCopies = "";

                log("    "$item.GetItemName(String(item.Class))$strCopies);
            }
            item = nextItem;
        }
        until (item == None);
    }
    else
        log("    Empty");

    GenerateTotalHealth();
    log("");
    log("  Health:");
    log("    Overall   - "$Health$"%");
    log("    Head      - "$HealthHead$"%");
    log("    Torso     - "$HealthTorso$"%");
    log("    Left arm  - "$HealthArmLeft$"%");
    log("    Right arm - "$HealthArmRight$"%");
    log("    Left leg  - "$HealthLegLeft$"%");
    log("    Right leg - "$HealthLegRight$"%");

    log("");
    log("  BioElectric Energy:");
    log("    "$Int(Energy)$"%");

    log("");
    log("  Credits:");
    log("    "$Credits);

    log("");
    log("  Skill Points:");
    log("    Available    - "$SkillPointsAvail);
    log("    Total Earned - "$SkillPointsTotal);

    log("");
    log("  Skills:");
    if (SkillSystem != None)
    {
        skill = SkillSystem.FirstSkill;
        while (skill != None)
        {
            if (skill.SkillName != "")
                log("    "$skill.SkillName$" - "$skill.skillLevelStrings[skill.CurrentLevel]);

            skill = skill.next;
        }
    }

    bHasAugs = False;
    log("");
    log("  Augmentations:");
    if (AugmentationSystem != None)
    {
        aug = AugmentationSystem.FirstAug;
        while (aug != None)
        {
            if (aug.bHasIt && (aug.AugmentationLocation != LOC_Default) && (aug.AugmentationName != ""))
            {
                bHasAugs = True;
                log("    "$aug.AugmentationName$" - Location: "$aug.AugLocsText[aug.AugmentationLocation]$" - Level: "$aug.CurrentLevel+1);
            }

            aug = aug.next;
        }
    }

    if (!bHasAugs)
        log("    None");

    log("");
    log("**** DXDumpInfo - END ****");
    log("");

    ClientMessage("Info dumped for user "$userName);
}


// ----------------------------------------------------------------------
// InvokeUIScreen()
//
// Calls DeusExRootWindow::InvokeUIScreen(), but first make sure 
// a modifier (Alt, Shift, Ctrl) key isn't being held down.
// ----------------------------------------------------------------------

function InvokeUIScreen(Class<DeusExBaseWindow> windowClass)
{
    local DeusExRootWindow root;
    root = DeusExRootWindow(rootWindow);
    if (root != None)
    {
        if ( root.IsKeyDown( IK_Alt ) || root.IsKeyDown( IK_Shift ) || root.IsKeyDown( IK_Ctrl ))
            return;

        root.InvokeUIScreen(windowClass);
    }
}

// ----------------------------------------------------------------------
// ResetConversationHistory()
//
// Clears any conversation history, used primarily when starting a 
// new game or travelling to new missions
// ----------------------------------------------------------------------

function ResetConversationHistory()
{
    if (conHistory != None)
    {
        CriticalDelete(conHistory);
        conHistory = None;
    }
}

// ======================================================================
// ======================================================================
// COLOR THEME MANAGER FUNCTIONS
// ======================================================================
// ======================================================================

// ----------------------------------------------------------------------
// CreateThemeManager()
// ----------------------------------------------------------------------

function CreateColorThemeManager()
{
    if (ThemeManager == None)
    {
        ThemeManager = Spawn(Class'ColorThemeManager', Self);

        // Add all default themes.

        // Menus
        ThemeManager.AddTheme(Class'ColorThemeMenu_Default');
        ThemeManager.AddTheme(Class'ColorThemeMenu_BlueAndGold');
        ThemeManager.AddTheme(Class'ColorThemeMenu_CoolGreen');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Cops');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Cyan');
        ThemeManager.AddTheme(Class'ColorThemeMenu_DesertStorm');
        ThemeManager.AddTheme(Class'ColorThemeMenu_DriedBlood');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Dusk');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Earth');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Green');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Grey');
        ThemeManager.AddTheme(Class'ColorThemeMenu_IonStorm');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Lava');
        ThemeManager.AddTheme(Class'ColorThemeMenu_NightVision');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Ninja');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Olive');
        ThemeManager.AddTheme(Class'ColorThemeMenu_PaleGreen');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Pastel');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Plasma');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Primaries');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Purple');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Red');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Seawater');
        ThemeManager.AddTheme(Class'ColorThemeMenu_SoylentGreen');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Starlight');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Steel');
        ThemeManager.AddTheme(Class'ColorThemeMenu_SteelGreen');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Superhero');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Terminator');
        ThemeManager.AddTheme(Class'ColorThemeMenu_Violet');

        // HUD
        ThemeManager.AddTheme(Class'ColorThemeHUD_Default');
        ThemeManager.AddTheme(Class'ColorThemeHUD_Amber');
        ThemeManager.AddTheme(Class'ColorThemeHUD_Cops');
        ThemeManager.AddTheme(Class'ColorThemeHUD_Cyan');
        ThemeManager.AddTheme(Class'ColorThemeHUD_DarkBlue');
        ThemeManager.AddTheme(Class'ColorThemeHUD_DesertStorm');
        ThemeManager.AddTheme(Class'ColorThemeHUD_DriedBlood');
        ThemeManager.AddTheme(Class'ColorThemeHUD_Dusk');
        ThemeManager.AddTheme(Class'ColorThemeHUD_Grey');
        ThemeManager.AddTheme(Class'ColorThemeHUD_IonStorm');
        ThemeManager.AddTheme(Class'ColorThemeHUD_NightVision');
        ThemeManager.AddTheme(Class'ColorThemeHUD_Ninja');
        ThemeManager.AddTheme(Class'ColorThemeHUD_PaleGreen');
        ThemeManager.AddTheme(Class'ColorThemeHUD_Pastel');
        ThemeManager.AddTheme(Class'ColorThemeHUD_Plasma');
        ThemeManager.AddTheme(Class'ColorThemeHUD_Primaries');
        ThemeManager.AddTheme(Class'ColorThemeHUD_Purple');
        ThemeManager.AddTheme(Class'ColorThemeHUD_Red');
        ThemeManager.AddTheme(Class'ColorThemeHUD_SoylentGreen');
        ThemeManager.AddTheme(Class'ColorThemeHUD_Starlight');
        ThemeManager.AddTheme(Class'ColorThemeHUD_SteelGreen');
        ThemeManager.AddTheme(Class'ColorThemeHUD_Superhero');
        ThemeManager.AddTheme(Class'ColorThemeHUD_Terminator');
        ThemeManager.AddTheme(Class'ColorThemeHUD_Violet');
    }
}

// ----------------------------------------------------------------------
// NextHUDColorTheme()
// 
// Cycles to the next available HUD color theme and squirts out 
// a "StylesChanged" event.
// ----------------------------------------------------------------------

exec function NextHUDColorTheme()
{
    if (ThemeManager != None)
    {
        ThemeManager.NextHUDColorTheme();
        DeusExRootWindow(rootWindow).ChangeStyle();
    }
}

// ----------------------------------------------------------------------
// Cycles to the next available Menu color theme and squirts out 
// a "StylesChanged" event.
// ----------------------------------------------------------------------

exec function NextMenuColorTheme()
{
    if (ThemeManager != None)
    {
        ThemeManager.NextMenuColorTheme();
        DeusExRootWindow(rootWindow).ChangeStyle();
    }
}

// ----------------------------------------------------------------------
// SetHUDBordersVisible()
// ----------------------------------------------------------------------

exec function SetHUDBordersVisible(bool bVisible)
{
    bHUDBordersVisible = bVisible;
}

// ----------------------------------------------------------------------
// GetHUDBordersVisible()
// ----------------------------------------------------------------------

function bool GetHUDBordersVisible()
{
    return bHUDBordersVisible;
}

// ----------------------------------------------------------------------
// SetHUDBorderTranslucency()
// ----------------------------------------------------------------------

exec function SetHUDBorderTranslucency(bool bNewTranslucency)
{
    bHUDBordersTranslucent = bNewTranslucency;
}

// ----------------------------------------------------------------------
// GetHUDBorderTranslucency()
// ----------------------------------------------------------------------

function bool GetHUDBorderTranslucency()
{
    return bHUDBordersTranslucent;
}

// ----------------------------------------------------------------------
// SetHUDBackgroundTranslucency()
// ----------------------------------------------------------------------

exec function SetHUDBackgroundTranslucency(bool bNewTranslucency)
{
    bHUDBackgroundTranslucent = bNewTranslucency;
}

// ----------------------------------------------------------------------
// GetHUDBackgroundTranslucency()
// ----------------------------------------------------------------------

function bool GetHUDBackgroundTranslucency()
{
    return bHUDBackgroundTranslucent;
}

// ----------------------------------------------------------------------
// SetMenuTranslucency()
// ----------------------------------------------------------------------

exec function SetMenuTranslucency(bool bNewTranslucency)
{
    bMenusTranslucent = bNewTranslucency;
}

// ----------------------------------------------------------------------
// GetMenuTranslucency()
// ----------------------------------------------------------------------

function bool GetMenuTranslucency()
{
    return bMenusTranslucent;
}

// ----------------------------------------------------------------------
// DebugInfo test functions
// ----------------------------------------------------------------------

exec function DebugCommand(string teststr)
{
    if (!bCheatsEnabled)
        return;

    if (GlobalDebugObj == None)
        GlobalDebugObj = new(Self) class'DebugInfo';

    if (GlobalDebugObj != None)
        GlobalDebugObj.Command(teststr);
}

exec function SetDebug(name cmd, name val)
{
    if (!bCheatsEnabled)
        return;

    if (GlobalDebugObj == None)
        GlobalDebugObj = new(Self) class'DebugInfo';

    Log("Want to setting Debug String " $ cmd $ " to " $ val);

    if (GlobalDebugObj != None)
        GlobalDebugObj.SetString(String(cmd),String(val));
}

exec function GetDebug(name cmd)
{
    local string temp;

    if (!bCheatsEnabled)
        return;

    if (GlobalDebugObj == None)
        GlobalDebugObj = new(Self) class'DebugInfo';

    if (GlobalDebugObj != None)
    {
        temp=GlobalDebugObj.GetString(String(cmd));
        Log("Debug String " $ cmd $ " has value " $ temp);
    }
}

exec function LogMsg(string msg)
{
    Log(msg);
}

simulated event Destroyed()
{
    if (GlobalDebugObj != None)
        CriticalDelete(GlobalDebugObj);

   ClearAugmentationDisplay();

   if (Role == ROLE_Authority)   
      CloseThisComputer(ActiveComputer);
   ActiveComputer = None;

    Super.Destroyed();
}

// ----------------------------------------------------------------------
// Actor Location and Movement commands
// ----------------------------------------------------------------------

exec function MoveActor(int xPos, int yPos, int zPos)
{
    local Actor            hitActor;
    local Vector           hitLocation, hitNormal;
    local Vector           position, line, newPos;

    if (!bCheatsEnabled)
        return;

    position    = Location;
    position.Z += BaseEyeHeight;
    line        = Vector(ViewRotation) * 4000;

    hitActor = Trace(hitLocation, hitNormal, position+line, position, true);
    if (hitActor != None)
    {
        newPos.x=xPos;
        newPos.y=yPos;
        newPos.z=zPos;
        // hitPawn = ScriptedPawn(hitActor);
        Log( "Trying to move " $ hitActor.Name $ " from " $ hitActor.Location $ " to " $ newPos);
        hitActor.SetLocation(newPos);
        Log( "Ended up at " $ hitActor.Location );
    }
}

exec function WhereActor(optional int Me)
{
    local Actor            hitActor;
    local Vector           hitLocation, hitNormal;
    local Vector           position, line, newPos;

    if (!bCheatsEnabled)
        return;

    if (Me==1)
        hitActor=self;
    else
    {
        position    = Location;
        position.Z += BaseEyeHeight;
        line        = Vector(ViewRotation) * 4000;
        hitActor    = Trace(hitLocation, hitNormal, position+line, position, true);
    }
    if (hitActor != None)
    {
        Log( hitActor.Name $ " is at " $ hitActor.Location );
        BroadcastMessage( hitActor.Name $ " is at " $ hitActor.Location );
    }
}

// ----------------------------------------------------------------------
// Easter egg functions
// ----------------------------------------------------------------------

function Matrix()
{
    if (Sprite == None)
    {
        Sprite = Texture(DynamicLoadObject("Extras.Matrix_A00", class'Texture'));
        ConsoleCommand("RMODE 6");
    }
    else
    {
        Sprite = None;
        ConsoleCommand("RMODE 5");
    }
}

exec function IAmWarren()
{
    if (!bCheatsEnabled)
        return;

    if (!bWarrenEMPField)
    {
        bWarrenEMPField = true;
        WarrenTimer = 0;
        WarrenSlot  = 0;
        ClientMessage("Warren's EMP Field activated");  // worry about localization?
    }
    else
    {
        bWarrenEMPField = false;
        ClientMessage("Warren's EMP Field deactivated");  // worry about localization?
    }
}

// ----------------------------------------------------------------------
// UsingChargedPickup
// ----------------------------------------------------------------------

function bool UsingChargedPickup(class<ChargedPickup> itemclass)
{
   local inventory CurrentItem;
   local bool bFound;

   bFound = false;
   
   for (CurrentItem = Inventory; ((CurrentItem != None) && (!bFound)); CurrentItem = CurrentItem.inventory)
   {
      if ((CurrentItem.class == itemclass) && (CurrentItem.bActive))
         bFound = true;
   }

   return bFound;
}

// ----------------------------------------------------------------------
// MultiplayerSpecificFunctions
// ----------------------------------------------------------------------

// ----------------------------------------------------------------------
// ReceiveFirstOptionSync()
// DEUS_EX AMSD I have to enumerate every 2#%#@%Ing argument???
// ----------------------------------------------------------------------

function ReceiveFirstOptionSync ( Name PrefZero, Name PrefOne, Name PrefTwo, Name PrefThree, Name PrefFour)
{
   local int i;
   local Name AugPriority[5];

   if (bFirstOptionsSynced == true)
   {
      return;
   }

   AugPriority[0] = PrefZero;
   AugPriority[1] = PrefOne;
   AugPriority[2] = PrefTwo;
   AugPriority[3] = PrefThree;
   AugPriority[4] = PrefFour;

   for (i = 0; ((i < ArrayCount(AugPrefs)) && (i < ArrayCount(AugPriority))); i++)
   {   
      AugPrefs[i] = AugPriority[i];
   }
   bFirstOptionsSynced = true;

   if (Role == ROLE_Authority)
   {
      if ((DeusExMPGame(Level.Game) != None) && (bSecondOptionsSynced))
      {
         DeusExMPGame(Level.Game).SetupAbilities(self);
      }
   }
}

// ----------------------------------------------------------------------
// ReceiveSecondOptionSync()
// DEUS_EX AMSD I have to enumerate every 2#%#@%Ing argument???
// ----------------------------------------------------------------------

function ReceiveSecondOptionSync ( Name PrefFive, Name PrefSix, Name PrefSeven, Name PrefEight)
{
   local int i;
   local Name AugPriority[9];

   if (bSecondOptionsSynced == true)
   {
      return;
   }

   AugPriority[5] = PrefFive;
   AugPriority[6] = PrefSix;
   AugPriority[7] = PrefSeven;
   AugPriority[8] = PrefEight;

   for (i = 5; ((i < ArrayCount(AugPrefs)) && (i < ArrayCount(AugPriority))); i++)
   {   
      AugPrefs[i] = AugPriority[i];
   }
   bSecondOptionsSynced = true;

   if (Role == ROLE_Authority)
   {
      if ((DeusExMPGame(Level.Game) != None) && (bFirstOptionsSynced))
      {
         DeusExMPGame(Level.Game).SetupAbilities(self);
      }
   }
}

// ----------------------------------------------------------------------
// ClientPlayAnimation
// ----------------------------------------------------------------------

simulated function ClientPlayAnimation( Actor src, Name anim, float rate, bool bLoop )
{
    if ( src != None )
    {
            //		if ( bLoop )
            //			src.LoopAnim(anim, ,rate);
            //		else
            src.PlayAnim(anim, ,rate);
    }
}

// ----------------------------------------------------------------------
// ClientSpawnProjectile
// ----------------------------------------------------------------------

simulated function ClientSpawnProjectile( class<projectile> ProjClass, Actor owner, Vector Start, Rotator AdjustedAim )
{
    local DeusExProjectile proj;

    proj = DeusExProjectile(Spawn(ProjClass, Owner,, Start, AdjustedAim));
    if ( proj != None )
    {
        proj.RemoteRole = ROLE_None;
        proj.Damage = 0;
    }
}

// ----------------------------------------------------------------------
// ClientSpawnHits
// ----------------------------------------------------------------------

simulated function ClientSpawnHits( bool bPenetrating, bool bHandToHand, Vector HitLocation, Vector HitNormal, Actor Other, float Damage)
{
   local TraceHitSpawner hitspawner;

   if (bPenetrating)
   {
      if (bHandToHand)
      {
         hitspawner = Spawn(class'TraceHitHandSpawner',Other,,HitLocation,Rotator(HitNormal));
      }
      else
      {
         hitspawner = Spawn(class'TraceHitSpawner',Other,,HitLocation,Rotator(HitNormal));
            hitspawner.HitDamage = Damage;
      }
   }
   else
   {
      if (bHandToHand)
      {
         hitspawner = Spawn(class'TraceHitHandNonPenSpawner',Other,,HitLocation,Rotator(HitNormal));
      }
      else
      {
         hitspawner = Spawn(class'TraceHitNonPenSpawner',Other,,HitLocation,Rotator(HitNormal));
      }
   }
   if (hitSpawner != None)
      hitspawner.HitDamage = Damage;
}

// ----------------------------------------------------------------------
// NintendoImmunityEffect()
// ----------------------------------------------------------------------
function NintendoImmunityEffect( bool on )
{
    bNintendoImmunity = on;

    if (bNintendoImmunity)
    {
        NintendoImmunityTime = Level.Timeseconds + NintendoDelay;
        NintendoImmunityTimeLeft = NintendoDelay;
    }
    else
        NintendoImmunityTimeLeft = 0.0;
}

// ----------------------------------------------------------------------
// GetAugPriority()
// Returns -1 if the player has the aug.
// Returns 0-8 (0 being higher priority) for the aug priority.
// If the player doesn't list the aug as a priority, returns the first
// unoccupied slot num (9 if all are filled).
// ----------------------------------------------------------------------
function int GetAugPriority( Augmentation AugToCheck)
{   
   local Name AugName;
   local int PriorityIndex;
   
   AugName = AugToCheck.Class.Name;

   if (AugToCheck.bHasIt)
      return -1;

   for (PriorityIndex = 0; PriorityIndex < ArrayCount(AugPrefs); PriorityIndex++)
   {
      if (AugPrefs[PriorityIndex] == AugName)
      {
         return PriorityIndex;
      }
      if (AugPrefs[PriorityIndex] == '')
      {
         return PriorityIndex;
      }
   }

   return PriorityIndex;   
}

// ----------------------------------------------------------------------
// GrantAugs()
// Grants augs in order of priority.
// Sadly, we do this on the client because propagation of requested augs
// takes so long.  
// ----------------------------------------------------------------------
function GrantAugs(int NumAugs)
{
   local Augmentation CurrentAug;
   local int PriorityIndex;
   local int AugsLeft;
    
   if (Role < ROLE_Authority)
      return;
   AugsLeft = NumAugs;

   for (PriorityIndex = 0; PriorityIndex < ArrayCount(AugPrefs); PriorityIndex++)
   {
      if (AugsLeft <= 0)
      {
         return;
      }
      if (AugPrefs[PriorityIndex] == '')
      {
         return;
      }
      for (CurrentAug = AugmentationSystem.FirstAug; CurrentAug != None; CurrentAug = CurrentAug.next)
      {
         if ((CurrentAug.Class.Name == AugPrefs[PriorityIndex]) && (CurrentAug.bHasIt == False))
         {
             AugmentationSystem.GivePlayerAugmentation(CurrentAug.Class);
                // Max out aug
                if (CurrentAug.bHasIt)
                    CurrentAug.CurrentLevel = CurrentAug.MaxLevel;
            AugsLeft = AugsLeft - 1;
         }
      }
   }
}

// ------------------------------------------------------------------------
// GiveInitialInventory()
// ------------------------------------------------------------------------

function GiveInitialInventory()
{
   local Inventory anItem;

   // Give the player a pistol.

   // spawn it.
   if ((!Level.Game.IsA('DeusExMPGame')) || (DeusExMPGame(Level.Game).bStartWithPistol))
   {
      anItem = Spawn(class'WeaponPistol');
      // "frob" it for pickup.  This will spawn a copy and give copy to player.
      anItem.Frob(Self,None);
      // Set it to be in belt (it will be the first inventory item)
      inventory.bInObjectBelt = True;
      // destroy original.
      anItem.Destroy();
      
      // Give some starting ammo.
      anItem = Spawn(class'Ammo10mm');
      DeusExAmmo(anItem).AmmoAmount=50;
      anItem.Frob(Self,None);
      anItem.Destroy();
   }

   // Give the player a medkit.
   anItem = Spawn(class'MedKit');
   anItem.Frob(Self,None);
   inventory.bInObjectBelt = True;
   anItem.Destroy();

    // Give them a lockpick and a multitool so they can make choices with skills
    // when they come across electronics and locks
    anItem = Spawn(class'Lockpick');
    anItem.Frob(Self,None);
    inventory.bInObjectBelt = True;
    anItem.Destroy();

   anItem = Spawn(class'Multitool');
    anItem.Frob(Self,None);
    inventory.bInObjectBelt = True;
    anItem.Destroy();
}

// ----------------------------------------------------------------------
// MultiplayerTick()
// Not the greatest name, handles single player ticks as well.  Basically
// anything tick style stuff that should be propagated to the server gets
// propagated as this one function call.
// ----------------------------------------------------------------------
function MultiplayerTick(float DeltaTime)
{
    local int burnTime;
    local float augLevel;

   Super.MultiplayerTick(DeltaTime);

   //If we've just put away items, reset this.
   if ((LastInHand != InHand) && (Level.Netmode == NM_Client) && (inHand == None))
   {
       ClientInHandPending = None;
   }

   LastInHand = InHand;
   
   if ((PlayerIsClient()) || (Level.NetMode == NM_ListenServer))
   {
      if ((ShieldStatus != SS_Off) && (DamageShield == None))
         DrawShield();
        if ( (NintendoImmunityTimeLeft > 0.0) && ( InvulnSph == None ))
            DrawInvulnShield();
      if (Style != STY_Translucent)
         CreateShadow();
      else
         KillShadow();
   }

   if (Role < ROLE_Authority)
      return;

   UpdateInHand();

   UpdatePoison(DeltaTime);
   
   if (lastRefreshTime < 0)
      lastRefreshTime = 0;

   lastRefreshTime = lastRefreshTime + DeltaTime;

    if (bOnFire)
    {
        if ( Level.NetMode != NM_Standalone )
            burnTime = Class'WeaponFlamethrower'.Default.mpBurnTime;
        else
            burnTime = Class'WeaponFlamethrower'.Default.BurnTime;
        burnTimer += deltaTime;
        if (burnTimer >= burnTime)
            ExtinguishFire();
    }
  
   if (lastRefreshTime < 0.25)
      return;

   if (ShieldTimer > 0)
      ShieldTimer = ShieldTimer - lastRefreshTime;

   if (ShieldStatus == SS_Fade)
      ShieldStatus = SS_Off;

   if (ShieldTimer <= 0)
   {
      if (ShieldStatus == SS_Strong)
         ShieldStatus = SS_Fade;
   }

    // If we have a drone active (post-death etc) and we're not using the aug, kill it off
    augLevel = AugmentationSystem.GetAugLevelValue(class'AugDrone');
    if (( aDrone != None ) && (augLevel == -1.0))
        aDrone.TakeDamage(100, None, aDrone.Location, vect(0,0,0), 'EMP');

    if ( Level.Timeseconds > ServerTimeLastRefresh )
    {
        SetServerTimeDiff( Level.Timeseconds );
        ServerTimeLastRefresh = Level.Timeseconds + 10.0;
    }
    
   MaintainEnergy(lastRefreshTime);
   UpdateTranslucency(lastRefreshTime);
    if ( bNintendoImmunity )
    {
        NintendoImmunityTimeLeft = NintendoImmunityTime - Level.Timeseconds;
        if ( Level.Timeseconds > NintendoImmunityTime )
            NintendoImmunityEffect( False );
    }
   RepairInventory();
   lastRefreshTime = 0;
}

// ----------------------------------------------------------------------

function ForceDroneOff()
{
    local AugDrone anAug;

   anAug = AugDrone(AugmentationSystem.FindAugmentation(class'AugDrone'));
    //foreach AllActors(class'AugDrone', anAug)			
   if (anAug != None)      
      anAug.Deactivate();
}

// ----------------------------------------------------------------------
// PlayerIsListenClient()
// Returns True if the current player is the "client" playing ON the
// listen server.
// ----------------------------------------------------------------------
function bool PlayerIsListenClient()
{
   return ((GetPlayerPawn() == Self) && (Level.NetMode == NM_ListenServer)); 
}

// ----------------------------------------------------------------------
// PlayerIsRemoteClient()
// Returns true if this player is the main player of this remote client
// -----------------------------------------------------------------------
function bool PlayerIsRemoteClient()
{
   return ((Level.NetMode == NM_Client) && (Role == ROLE_AutonomousProxy));
}

// ----------------------------------------------------------------------
// PlayerIsClient()
// Returns true if the current player is the "client" playing ON the
// listen server OR a remote client
// ----------------------------------------------------------------------
function bool PlayerIsClient()
{
   return (PlayerIsListenClient() || PlayerIsRemoteClient());
}

// ----------------------------------------------------------------------
// DrawShield()
// ----------------------------------------------------------------------
simulated function DrawShield()
{
    local ShieldEffect shield;

   if (DamageShield != None)
   {
      return;
   }

    shield = Spawn(class'ShieldEffect', Self,, Location, Rotation);
    if (shield != None)
   {
        shield.SetBase(Self);
      shield.RemoteRole = ROLE_None;
      shield.AttachedPlayer = Self;
   }

   DamageShield = shield;
}

// ----------------------------------------------------------------------
// DrawInvulnShield()
// ----------------------------------------------------------------------
simulated function DrawInvulnShield()
{
    if (( InvulnSph != None ) || (Level.NetMode == NM_Standalone))
        return;

    InvulnSph = Spawn(class'InvulnSphere', Self, , Location, Rotation );
    if ( InvulnSph != None )
    {
        InvulnSph.SetBase( Self );
        InvulnSph.RemoteRole = ROLE_None;
        InvulnSph.AttachedPlayer = Self;
        InvulnSph.LifeSpan = NintendoImmunityTimeLeft;
    }
}

// ----------------------------------------------------------------------
// CreatePlayerTracker()
// ----------------------------------------------------------------------
simulated function CreatePlayerTracker()
{
   local MPPlayerTrack PlayerTracker;

   PlayerTracker = Spawn(class'MPPlayerTrack');  
   PlayerTracker.AttachedPlayer = Self;
}

// ----------------------------------------------------------------------
// DisconnectPlayer()
// ----------------------------------------------------------------------
exec function DisconnectPlayer()
{
   if (DeusExRootWindow(rootWindow) != None)
        DeusExRootWindow(rootWindow).ClearWindowStack();
   
   if (PlayerIsRemoteClient())
      ConsoleCommand("disconnect");
   
   if (PlayerIsListenClient())
      ConsoleCommand("start dx.dx");
}

exec function ShowPlayerPawnList()
{
   local pawn curpawn;

   for (curpawn = level.pawnlist; curpawn != none; curpawn = curpawn.nextpawn)
      log("======>Pawn is "$curpawn);
}

// ----------------------------------------------------------------------
// KillShadow
// ----------------------------------------------------------------------
simulated function KillShadow()
{
   if (Shadow != None)
      Shadow.Destroy();
   Shadow = None;
}

// ----------------------------------------------------------------------
// CreateShadow
// ----------------------------------------------------------------------
simulated function CreateShadow()
{
   if (Shadow == None)
   {
      Shadow = Spawn(class'Shadow', Self,, Location-vect(0,0,1)*CollisionHeight, rot(16384,0,0));
      if (Shadow != None)
      {
         Shadow.RemoteRole = ROLE_None;
      }
   }
}

// ----------------------------------------------------------------------
// LocalLog
// ----------------------------------------------------------------------
function LocalLog(String S)
{
    if (( Player != None ) && ( Player.Console != None ))
        Player.Console.AddString(S);
}

// ----------------------------------------------------------------------
// ShowDemoSplash()
// ----------------------------------------------------------------------
function ShowDemoSplash()
{
    local DeusExRootWindow root;

    root = DeusExRootWindow(rootWindow);
    if (root != None)
        root.PushWindow(Class'DemoSplashWindow');
}

// ----------------------------------------------------------------------
// VerifyConsole()
// Verifies that console is Engine.Console.  If you want something different,
// override this in a subclassed player class.
// ----------------------------------------------------------------------

function VerifyConsole(Class<Console> ConsoleClass)
{
    local bool bCheckPassed;
    
    bCheckPassed = True;

    if (Player.Console == None)
        bCheckPassed = False;
    else if (Player.Console.Class != ConsoleClass)
        bCheckPassed = False;

    if (bCheckPassed == False)
        FailConsoleCheck();
}

// ----------------------------------------------------------------------
// VerifyRootWindow()
// Verifies that the root window is the right kind of root window, since
// it can be changed in the ini
// ----------------------------------------------------------------------
function VerifyRootWindow(Class<DeusExRootWindow> WindowClass)
{
    local bool bCheckPassed;
    
    bCheckPassed = True;

    if (RootWindow == None)
        bCheckPassed = False;
    else if (RootWindow.Class != WindowClass)
        bCheckPassed = False;

    if (bCheckPassed == False)
        FailRootWindowCheck();
}

// ----------------------------------------------------------------------
// FailRootWindowCheck()
// ----------------------------------------------------------------------
function FailRootWindowCheck()
{
    if (Level.Game.IsA('DeusExGameInfo'))
        DeusExGameInfo(Level.Game).FailRootWindowCheck(Self);
}

// ----------------------------------------------------------------------
// FailConsoleCheck()
// ----------------------------------------------------------------------
function FailConsoleCheck()
{
    if (Level.Game.IsA('DeusExGameInfo'))
        DeusExGameInfo(Level.Game).FailConsoleCheck(Self);
}

// ----------------------------------------------------------------------
// Possess()
// ----------------------------------------------------------------------
event Possess()
{
    Super.Possess();

    if (Level.Netmode == NM_Client)
    {
        ClientPossessed();
    }
}

// ----------------------------------------------------------------------
// ClientPossessed()
// ----------------------------------------------------------------------
function ClientPossessed()
{
    if (Level.Game.IsA('DeusExGameInfo'))
        DeusExGameInfo(Level.Game).ClientPlayerPossessed(Self);
}

// ----------------------------------------------------------------------
// ForceDisconnect
// ----------------------------------------------------------------------
function ForceDisconnect(string Message)
{
    player.Console.AddString(Message);
    DisconnectPlayer();
}


// ----------------------------------------------------------------------
// ----------------------------------------------------------------------

defaultproperties
{
     TruePlayerName="JC Denton"
     CombatDifficulty=1.000000
     SkillPointsTotal=5000
     SkillPointsAvail=5000
     Credits=500
     Energy=100.000000
     EnergyMax=100.000000
     MaxRegenPoint=25.000000
     RegenRate=1.500000
     MaxFrobDistance=112.000000
     maxInvRows=6
     maxInvCols=5
     bBeltIsMPInventory=True
     RunSilentValue=1.000000
     ClotPeriod=30.000000
     strStartMap="01_NYC_UNATCOIsland"
     bObjectNames=True
     bNPCHighlighting=True
     bSubtitles=True
     bAlwaysRun=True
     logTimeout=5.000000
     maxLogLines=4
     bHelpMessages=True
     bObjectBeltVisible=True
     bHitDisplayVisible=True
     bAmmoDisplayVisible=True
     bAugDisplayVisible=True
     bDisplayAmmoByClip=True
     bCompassVisible=True
     bCrosshairVisible=True
     bAutoReload=True
     bDisplayAllGoals=True
     bHUDShowAllAugs=True
     bShowAmmoDescriptions=True
     bConfirmSaveDeletes=True
     bConfirmNoteDeletes=True
     AugPrefs(0)=AugVision
     AugPrefs(1)=AugHealing
     AugPrefs(2)=AugSpeed
     AugPrefs(3)=AugDefense
     AugPrefs(4)=AugBallistic
     AugPrefs(5)=AugShield
     AugPrefs(6)=AugEMP
     AugPrefs(7)=AugStealth
     AugPrefs(8)=AugAqualung
     MenuThemeName="Default"
     HUDThemeName="Default"
     bHUDBordersVisible=True
     bHUDBordersTranslucent=True
     bHUDBackgroundTranslucent=True
     bMenusTranslucent=True
     InventoryFull="You don't have enough room in your inventory to pick up the %s"
     TooMuchAmmo="You already have enough of that type of ammo"
     TooHeavyToLift="It's too heavy to lift"
     CannotLift="You can't lift that"
     NoRoomToLift="There's no room to lift that"
     CanCarryOnlyOne="You can only carry one %s"
     CannotDropHere="Can't drop that here"
     HandsFull="Your hands are full"
     NoteAdded="Note Received - Check DataVault For Details"
     GoalAdded="Goal Received - Check DataVault For Details"
     PrimaryGoalCompleted="Primary Goal Completed"
     SecondaryGoalCompleted="Secondary Goal Completed"
     EnergyDepleted="Bio-electric energy reserves depleted"
     AddedNanoKey="%s added to Nano Key Ring"
     HealedPointsLabel="Healed %d points"
     HealedPointLabel="Healed %d point"
     SkillPointsAward="%d skill points awarded"
     QuickSaveGameTitle="Quick Save"
     WeaponUnCloak="Weapon drawn... Uncloaking"
     TakenOverString="I've taken over the "
     HeadString="Head"
     TorsoString="Torso"
     LegsString="Legs"
     WithTheString=" with the "
     WithString=" with "
     PoisonString=" with deadly poison"
     BurnString=" with excessive burning"
     NoneString="None"
     MPDamageMult=1.000000
     bCanStrafe=True
     MeleeRange=50.000000
     AccelRate=2048.000000
     FovAngle=75.000000
     Intelligence=BRAINS_HUMAN
     AngularResolution=0.500000
     Alliance=Player
     DrawType=DT_Mesh
     SoundVolume=64
     RotationRate=(Pitch=3072,Yaw=65000,Roll=2048)
     BindName="JCDenton"
     FamiliarName="JC Denton"
     UnfamiliarName="JC Denton"
}

Overview Package Class Source Class tree Glossary
previous class      next class frames      no frames
Class file time: Mon 8/11/2021 16:22:50.000 - Creation time: Mon 8/11/2021 16:31:25.742 - Created with UnCodeX