My favorites | Sign in
Project Logo
          
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
; set these the same as your actual JA configuration
; (these could be extracted from jaconfig.cfg in the future)
; cannot use Alt here! Hitting Alt in JA seems to cause movement (and other?) keys to sneak through AHKs hook
bind_moveForward := "w"
bind_moveLeft := "a"
bind_moveBack := "s"
bind_moveRight := "d"

bind_jump := "Space"
bind_crouch := "Shift" ; do not use Alt

bind_attack := "LButton"
bind_altAttack := "RButton"

bind_forcePush := "Ctrl"
bind_forcePull := "Alt" ; Alt seems okay here
bind_forceGrip := "o"
bind_forceMindTrick := "MButton"

bind_saberStyle := "l"

bind_lightSaber := "1"

specialBind_lungeAttack := "WheelDown"
specialBind_flipAttack := "WheelUp"
SetCapsLockState AlwaysOff
specialBind_cartWheelLeft := "CapsLock"
specialBind_cartWheelRight := "f"
specialBind_cartWheelForward := "v"

SetBatchLines 15 ; the speed at which the script runs

/*
todo:
need to do some memory scanning to reliably set the haveAllSaberStyles variable
so that changing saber stances for the special moves will work reliably
no matter whether you went the 3 style route or switched to something else

also need to just consider the dual/saber & saberstaff stances in general :P

need a more reliable saberStyleStaticPtr

need a more intelligent/reliable mindtrick
there's source code to Jedi Academy mods that probably lend insight to how mindtrick/etc works, for instance:
http://www.google.com/codesearch?hl=en&q="typedef+struct+entityState_s"+jedi+show:PlqG3-Mp1So:SgofosJwKnY:TvUB2_Qc0Pg&sa=N&cd=1&ct=rc&cs_p=http://duelers.jk2files.com/duelers-ja-code.zip&cs_f=duelers-ja-code/JKA_mp(SDK)/codemp/game/q_shared.h#l2675


future ideas:
record avg. duration of each animation with a running sum, count, and average
determine various sequences of animations for each attack & determine their duration
determine frequency of these sequences if random (probably not too random, or 50/50 if anything, is my guess)
recording inflicted damage for these would yield the most effective attacks

automatically scan and identity nearby entities, turn to face, perform an action
and turn back all instantly (force pull a health pack, toss a saber, etc.)

some notes:
changing an entities position only works for animating items (try the grate fan in front of you in the free the prisoners level)
clearly some sort of code must be executed to truly move an item

setting a character's health to 0 causes them to completely freeze, stop firing at you etc.
at this stage if you touch them they will perform the actual death animation sequence,
they'll also be removed if unattended
*/

#SingleInstance force
#Include %A_ScriptDir%\memory management.ahk

jaWindow := "Jedi Knight"
jaProcessName := "jasp.exe"

; pointers
entityArrayStaticPtr := 0x00C2A18C
entityArrayOffset1 := 0x40
entityArrayOffset2 := 0x0
entityStructSize := 0x4E4

;forceValueStaticPtr := 0x019A7EA0 ; actually non-static but seems reliable (so far)
;forceValueOffset1 := 0x1250

idUnderCursorStaticPtr := 0x00C91A18
idUnderCursorOffset1 := 0x4834
idUnderCursorOffset2 := 0x0

; this is indeed static, but it's no good, I've had it fail on me
saberStyleStaticPtr := 0x2070561c

SABERSTYLE_FAST := 1
SABERSTYLE_MEDIUM := 2
SABERSTYLE_STRONG := 3

; they default to 4 bytes
ENTITY_POS_X := 0x18
ENTITY_POS_X_TYPE := "Float"
ENTITY_POS_Y := 0x1C
ENTITY_POS_Y_TYPE := "Float"
ENTITY_POS_Z := 0x20
ENTITY_POS_Z_TYPE := "Float"
ENTITY_LOOK_Y := 0x3C
ENTITY_LOOK_Y_TYPE := "Float"
ENTITY_LOOK_X := 0x40
ENTITY_LOOK_X_TYPE := "Float"
ENTITY_TYPE := 0xA0
ENTITY_TYPE_TYPE := "Int"
ENTITY_ANIM := 0xC8
ENTITY_ANIM_TYPE := "UInt"
ENTITY_UNKNOWN := 0x12E
ENTITY_UNKNOWN_TYPE := "Int"
ENTITY_UNKNOWN_BYTES := 2
ENTITY_HEALTH := 0x244
ENTITY_HEALTH_TYPE := "UInt"

; it's more than just this... a char can have a value of 0 here and NOT be mindtricked, like pretty much all
; the chars in the mission where you've been captured... hm
ENTITY_MINDTRICKED := 0x2CC
ENTITY_MINDTRICKED_TYPE := "UInt"

ENTITY_ITEM_EFFECT := 0x4D0
ENTITY_ITEM_EFFECT_TYPE := "Int"
ENTITY_ITEM_EFFECT_BYTES := 2

SELF := 0
BACKDROP := 1022

; some item types
ITEM_DETONATOR := 35
ITEM_TRIPMINE := 36

; confirmed
ANIM_FORCECHOKED := 1322
ANIM_KNOCKEDDOWN := 1220
ANIM_HANDSBEHINDBACK := 922

; animation performed can vary by type of saber, saber stance,
; and enemies saber and saber stance, and who knows what else
; the names should really be refactored to be more specific if/when this is determined
ANIM_FORCECHOKED_2 := 1320
ANIM_FORCEDRAINED := 1362
ANIM_SABERLOCK := 841 ; confirmed
ANIM_SABERLOCK_2 := 848
ANIM_SABERLOCK_3 := 849
ANIM_SABERLOCK_4 := 742 ; confirmed; with guy with dual sabers?
ANIM_SABERLOCK_5 := 838 ; confirmed; uh... single saber vs. single saber? dunno
ANIM_SABERLOCK_6 := 792 ; dual sabers vs. dual sabers?

ANIM_FORCEBLOCK := 1330
ANIM_FORCEBLOCK_2 := 1332 ; maybe?

scriptStart := A_TickCount

; point at backdrop by default
idUnderCursor := BACKDROP

InitDebugGUI()

#IfWinActive Jedi Knight
Hotkey %bind_moveForward%, label_moveForward
Hotkey %bind_moveLeft%, label_moveLeft
Hotkey %bind_moveBack%, label_moveBack
Hotkey %bind_moveRight%, label_moveRight

Hotkey ~%bind_moveForward% Up, label_moveForward_release
Hotkey ~%bind_moveLeft% Up, label_moveLeft_release
Hotkey ~%bind_moveBack% Up, label_moveBack_release
Hotkey ~%bind_moveRight% Up, label_moveRight_release

Hotkey %specialBind_lungeAttack%, label_lungeAttack
Hotkey %specialBind_flipAttack%, label_flipAttack
Hotkey %specialBind_cartWheelLeft%, label_cartWheelLeft
Hotkey %specialBind_cartWheelRight%, label_cartWheelRight
Hotkey %specialBind_cartWheelForward%, label_cartWheelForward

Loop {
CheckProcess(jaProcessName)

IfWinNotActive %jaWindow%
continue

entityArrayPtr := ReadPtr(entityArrayStaticPtr) + entityArrayOffset1
entityArrayPtr := ReadPtr(entityArrayPtr) + entityArrayOffset2

idUnderCursorPtr := ReadPtr(idUnderCursorStaticPtr) + idUnderCursorOffset1
idUnderCursorPtr := ReadPtr(idUnderCursorPtr) + idUnderCursorOffset2
pendingIdUnderCursor := ReadMemory(idUnderCursorPtr, "UInt", 4)
if (pendingIdUnderCursor <> BACKDROP && pendingIdUnderCursor <> SELF)
idUnderCursor := pendingIdUnderCursor

EntityDebugText(0, "Own")
EntityDebugText(idUnderCursor, "Char")

SpecialMoves()

; mindtricks only non-mindtricked entities,
; and works continuously while the key is held down
if (GetKeyState(bind_forceMindTrick, "p")) {
awareOfPlayer := GetPropI(idUnderCursor, "ENTITY_MINDTRICKED") <> 0
if (awareOfPlayer || InStandingAnim(idUnderCursor) && InInitialPosition(idUnderCursor))
SendEvent {%bind_forceMindTrick%}
}
; screwing around with a quick force grip floor smash,
; doesn't work reliably
else if (GetKeyState(bind_forceGrip, "p")) {
enemyAnim := GetPropI(idUnderCursor, "ENTITY_ANIM")
if ( enemyAnim = ANIM_FORCECHOKED || enemyAnim = ANIM_FORCECHOKED_2 ) {
MouseMove, 0, 5000, 1, R
Sleep 100
MouseMove, 0, 5000, 1, R
Sleep 100

MouseMove, 0, -5000, 1, R
Sleep 100
MouseMove, 0, -5000, 1, R
Sleep 100
}
}

Gui Submit, NoHide
; instant death to whatever character you look at with this (friendlies too atm)
if (killTarget) {
isChar := GetPropI(idUnderCursor, "ENTITY_ANIM") <> 0
if (isChar && GetPropI(idUnderCursor, "ENTITY_HEALTH") <> 0)
SetPropI(idUnderCursor, "ENTITY_HEALTH", 0)
}

;forceValuePtr := ReadPtr(forceValueStaticPtr) + forceValueOffset1
;forceValue := ReadMemory(forceValuePtr, "Char", 1)

AnimationReaction(ANIM_FORCECHOKED, bind_forcePull)
AnimationReaction(ANIM_KNOCKEDDOWN, bind_jump)

/*
AnimationReaction(ANIM_FORCEDRAINED, bind_forcePull)

; a way to instantly break saber locks and such
AnimationReaction(ANIM_SABERLOCK, bind_attack)
AnimationReaction(ANIM_SABERLOCK_2, bind_attack)
AnimationReaction(ANIM_SABERLOCK_3, bind_attack)
AnimationReaction(ANIM_SABERLOCK_4, bind_attack)
AnimationReaction(ANIM_SABERLOCK_5, bind_attack)
AnimationReaction(ANIM_SABERLOCK_6, bind_attack)
AnimationReaction(ANIM_SABERLOCK_7, bind_attack)
*/

;AnimationReaction(ANIM_FORCEPUSHED, bind_forcePush)
;AnimationReaction(ANIM_FORCEPUSHED_2, bind_forcePush)

;clipboard := SubStr(entityStructStart, 3)
}
return

updateDisplay:
GuiControl Text, Display, %displayText%
return

AnimationReaction(animation, reactionKey) {
local ownAnimation
ownAnimation := GetPropI(0, "ENTITY_ANIM")
if (ownAnimation = animation) {
Loop {
IfWinNotActive %jaWindow%
continue

SendEvent {%reactionKey%}
Sleep 10
ownAnimation := GetPropI(0, "ENTITY_ANIM")
if (ownAnimation <> animation) {
if (animation = ANIM_FORCECHOKED)
SendEvent %bind_lightSaber%
return true
}
}
}
return false
}

EntityDebugText(entityIndex, controlName) {
global globalEntityIndex := entityIndex

GuiControl Text, % controlName
, % "Index: " . entityIndex
. "`nAddress: " . EntityStructStart(entityIndex)
. "`nHealth: " . GetProp("ENTITY_HEALTH")
. "`nAnimation: " . GetProp("ENTITY_ANIM")
. "`nX: " . GetProp("ENTITY_POS_X") . " Y: " . GetProp("ENTITY_POS_Y") . " Z: " . GetProp("ENTITY_POS_Z")
. "`nLookX: " . GetProp("ENTITY_LOOK_X") . " LookY: " . GetProp("ENTITY_LOOK_Y")
. "`nType: " . GetProp("ENTITY_TYPE") . " Distance: " . GetDist()
. "`nUnknown: " . GetProp("ENTITY_UNKNOWN") . " Entity Item Effect: " . GetProp("ENTITY_ITEM_EFFECT")
. "`nEntity Mind Tricked?: " . GetProp("ENTITY_MINDTRICKED")
}

; can't just use BlockInput to stop character movement because then we won't be able to know the real
; physical state of keys because BlockInput will block their release
HaltMovement() {
global
inSpecialMove := true

SendInput {%bind_moveForward% Up}{%bind_moveLeft% Up}{%bind_moveBack% Up}{%bind_moveRight% Up}
Sleep 100 ; adjust based on game, but it will take a moment before the player really stops
}

RestoreMovement() {
global
if %bind_moveForward%Key
SendEvent {%bind_moveForward% Down}
if %bind_moveLeft%Key
SendEvent {%bind_moveLeft% Down}
if %bind_moveBack%Key
SendEvent {%bind_moveBack% Down}
if %bind_moveRight%Key
SendEvent {%bind_moveRight% Down}

inSpecialMove := false
}

DoProp(operation, entityIndex, property, value = "") {
local ptr, byteNum
ptr := EntityStructStart(entityIndex) + %property%

byteNum := %property%_BYTES
if (byteNum = "")
byteNum := 4

return MemoryOp(operation, ptr, %property%_TYPE, byteNum, value)
}

EntityStructStart(entityIndex) {
global
return entityArrayPtr + (entityIndex * entityStructSize)
}

GetPropI(entityIndex, property) {
global MEMORYOP_READ
return DoProp(MEMORYOP_READ, entityIndex, property)
}

GetProp(property) {
global globalEntityIndex
return GetPropI(globalEntityIndex, property)
}

SetPropI(entityIndex, property, value) {
global MEMORYOP_WRITE
return DoProp(MEMORYOP_WRITE, entityIndex, property, value)
}

SetProp(property, value) {
global globalEntityIndex
return SetPropI(globalEntityIndex, property, value)
}

GetDist() {
; all variables are local
thisX := GetProp("ENTITY_POS_X")
thisY := GetProp("ENTITY_POS_Y")
thisZ := GetProp("ENTITY_POS_Z")

selfX := GetPropI(0, "ENTITY_POS_X")
selfY := GetPropI(0, "ENTITY_POS_Y")
selfZ := GetPropI(0, "ENTITY_POS_Z")

deltaX := selfX - thisX
deltaY := selfY - thisY
deltaZ := selfZ - thisZ

xyDistance := Sqrt(deltaX ** 2 + deltaY ** 2)
xyzDistance := Sqrt(xyDistance ** 2 + deltaZ ** 2)
return xyzDistance
}

MotionKeyPress(key) {
local smallTickCount
%key%Key := true
if (inSpecialMove)
return

SendEvent {%key% Down}
;smallTickCount := A_TickCount - scriptStart
;GuiControl Text, %key%P, %key% pressed %smallTickCount%
}

; labels instead of HotKey declarations with :: because the :: style doesn't take variables :(
label_moveForward:
MotionKeyPress(bind_moveForward)
return
label_moveLeft:
MotionKeyPress(bind_moveLeft)
return
label_moveBack:
MotionKeyPress(bind_moveBack)
return
label_moveRight:
MotionKeyPress(bind_moveRight)
return

MotionKeyRelease(key) {
local smallTickCount
%key%Key := false
if (inSpecialMove)
return

SendEvent {%key% Up}
;smallTickCount := A_TickCount - scriptStart
;GuiControl Text, %key%R, %key% released %smallTickCount%
}

label_moveForward_release:
MotionKeyRelease(bind_moveForward)
return
label_moveLeft_release:
MotionKeyRelease(bind_moveLeft)
return
label_moveBack_release:
MotionKeyRelease(bind_moveBack)
return
label_moveRight_release:
MotionKeyRelease(bind_moveRight)
return

InitDebugGUI() {
global
Gui +AlwaysOnTop
Gui Add, Edit, R9 W500 vChar
Gui Add, Edit, R9 W500 vOwn
Gui Add, Edit, W500 v%bind_moveForward%P
Gui Add, Edit, W500 v%bind_moveForward%R
Gui Add, Edit, W500 v%bind_moveLeft%P
Gui Add, Edit, W500 v%bind_moveLeft%R
Gui Add, Edit, W500 v%bind_moveBack%P
Gui Add, Edit, W500 v%bind_moveBack%R
Gui Add, Edit, W500 v%bind_moveRight%P
Gui Add, Edit, W500 v%bind_moveRight%R
Gui Add, Edit, W500 vDisplay
Gui Add, Checkbox, vkillTarget, Kill On Mouse Hover
Gui Show, NoActivate x2200 y100, JA Debug
SetTimer updateDisplay
}

SaberCycleCount(startStyle, endStyle) {
local result
if (! haveAllSaberStyles) {
; only 2 styles to cycle through
if (startStyle = endStyle)
return 0
else
return 1
}
; 3 styles to cycle through

; have them start at 0
startStyle -= 1
endStyle -= 1

result := 3 - startStyle
result := Mod(result, 3)
result := result + endStyle
result := Mod(result, 3)

return result
}

SaberCycle(saberStyle) {
local currentSaberStyle := ReadByte(saberStyleStaticPtr)
cycleCount := SaberCycleCount(currentSaberStyle, saberStyle)
returnCycleCount := SaberCycleCount(saberStyle, currentSaberStyle)
}

label_lungeAttack:
key%specialBind_lungeAttack% := true
return
label_flipAttack:
key%specialBind_flipAttack% := true
return
label_cartWheelLeft:
key%specialBind_cartWheelLeft% := true
return
label_cartWheelRight:
key%specialBind_cartWheelRight% := true
return
label_cartWheelForward:
key%specialBind_cartWheelForward% := true
return

; NOTE: delays are going to be different when running at different frames per second!
; should be refactored for this
SpecialMoves() {
global
if (key%specialBind_lungeAttack%) {
; single saber, fast style, lunge attack
SaberCycle(SABERSTYLE_FAST)
HaltMovement()
SendEvent {%bind_crouch% Down}{%bind_moveForward% Down}{%bind_saberStyle% %cycleCount%}
Sleep 50
SendEvent {%bind_attack%}
Sleep 50
SendEvent {%bind_saberStyle% %returnCycleCount%}{%bind_moveForward% Up}{%bind_crouch% Up}
RestoreMovement()
key%specialBind_lungeAttack% := false
}
else if (key%specialBind_flipAttack%) {
; single saber, medium style, flip attack
; with functions to accurately & instantaneously turn the player we could
; have one of these flip spin you 180 at the end to actually keep facing forward
SaberCycle(SABERSTYLE_MEDIUM)
HaltMovement()
SendEvent {%bind_moveForward% Down}{%bind_jump% Down}{%bind_saberStyle% %cycleCount%}{%bind_attack%}
Sleep 100 ; maybe 50 when running at a better FPS
SendEvent {%bind_saberStyle% %returnCycleCount%}{%bind_jump% Up}{%bind_moveForward% Up}
RestoreMovement()
key%specialBind_flipAttack% := false
}
else if (key%specialBind_cartWheelLeft%) {
; single saber, fast/medium/strong style, cartwheel (left)
HaltMovement()
SendEvent {%bind_moveLeft% Down}
Sleep 50
SendEvent {%bind_jump% Down}{%bind_attack% Down}
Sleep 50
SendEvent {%bind_jump% Up}{%bind_moveLeft% Up}
Sleep 1200
SendEvent {%bind_attack% Up}
RestoreMovement()
key%specialBind_cartWheelLeft% := false
}
else if (key%specialBind_cartWheelRight%) {
; single saber, fast/medium/strong style, cartwheel (right)
HaltMovement()
SendEvent {%bind_moveRight% Down}
Sleep 50
SendEvent {%bind_jump% Down}{%bind_attack% Down}
Sleep 50
SendEvent {%bind_jump% Up}{%bind_moveRight% Up}
Sleep 1200
SendEvent {%bind_attack% Up}
RestoreMovement()
key%specialBind_cartWheelRight% := false
}
else if (key%specialBind_cartWheelForward%) {
; this one needs lots of work, specifically, reliable functions
; for turning the player to face certain coordinates instead of
; this unreliable & often faulty method
HaltMovement()
SendEvent {%bind_moveLeft% Down}

MouseMove, 5000, 0, 0, R
Sleep 50
MouseMove, 5000, 0, 0, R

SendEvent {%bind_jump% Down}{%bind_attack% Down}
Sleep 50
SendEvent {%bind_jump% Up}{%bind_moveLeft% Up}

MouseMove, -5000, 0, 0, R
Sleep 50
MouseMove, -5000, 0, 0, R

RestoreMovement()
Sleep 1150
SendEvent {%bind_attack% Up}
key%specialBind_cartWheelForward% := false
}
}

; a couple temporary functions until I find a better method for determining
; when the player should mindtrick
InInitialPosition(entityIndex) {
oPosX := GetPropI(entityIndex, "ENTITY_POS_X")
oPosY := GetPropI(entityIndex, "ENTITY_POS_Y")

SetFormat float, 0.0
posX := oPosX + 0
posY := oPosY + 0
SetFormat float, 0.6

; not the integer *type*, but rather, does the decimal portion = ".00000"
posIsInteger := oPosX = posX && oPosY = posY
; if the entity had moved, its position wouldn't be a perfect nice round integer
return posIsInteger
}

InStandingAnim(entityIndex) {
anim := GetPropI(entityIndex, "ENTITY_ANIM")
return anim = ANIM_HANDSBEHINDBACK || 920 || 921
}

GuiEscape:
WinClose
return

GuiClose:
CloseHandle(processHandle)
ExitApp
Show details Hide details

Change log

r4 by Christopher.Galpin on Dec 03, 2008   Diff
Still just adding more comments/detail so
this can be a better example. Renamed
bind_forceChoke -> bind_forceGrip.
Go to: 
Project members, sign in to write a code review

Older revisions

r3 by Christopher.Galpin on Jun 09, 2008   Diff
Clarified & added some comments.
r2 by Christopher.Galpin on Jun 09, 2008   Diff
Initial import.
All revisions of this file

File info

Size: 17829 bytes, 591 lines
Hosted by Google Code