Justifier: Add controller implementation
This commit is contained in:
parent
36df91aba0
commit
e190699deb
|
@ -8679,7 +8679,7 @@ SLES-00578:
|
||||||
name: "Area 51 (Europe) (En,Fr,De,Es)"
|
name: "Area 51 (Europe) (En,Fr,De,Es)"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "GT Interactive / Midway"
|
publisher: "GT Interactive / Midway"
|
||||||
|
@ -8702,7 +8702,7 @@ SLES-03783:
|
||||||
name: "Area 51 (Europe) (En,Fr,De,Es) (Midway Classics)"
|
name: "Area 51 (Europe) (En,Fr,De,Es) (Midway Classics)"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "GT Interactive / Midway"
|
publisher: "GT Interactive / Midway"
|
||||||
|
@ -8725,7 +8725,7 @@ SLPS-00726:
|
||||||
name: "Area 51 (Japan)"
|
name: "Area 51 (Japan)"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Soft Bank"
|
publisher: "Soft Bank"
|
||||||
|
@ -8745,7 +8745,7 @@ SLPS-00725:
|
||||||
name: "Area 51 (Japan) (Special Pack)"
|
name: "Area 51 (Japan) (Special Pack)"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Soft Bank"
|
publisher: "Soft Bank"
|
||||||
|
@ -8768,7 +8768,7 @@ SLUS-00164:
|
||||||
versionTested: "0.1-986-gfc911de1"
|
versionTested: "0.1-986-gfc911de1"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Midway"
|
publisher: "Midway"
|
||||||
|
@ -31509,7 +31509,7 @@ SLES-00292:
|
||||||
name: "Crypt Killer (Europe)"
|
name: "Crypt Killer (Europe)"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Konami"
|
publisher: "Konami"
|
||||||
developer: "Konami"
|
developer: "Konami"
|
||||||
|
@ -31528,7 +31528,7 @@ SLUS-00335:
|
||||||
name: "Crypt Killer (USA)"
|
name: "Crypt Killer (USA)"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Konami"
|
publisher: "Konami"
|
||||||
developer: "Konami"
|
developer: "Konami"
|
||||||
|
@ -37025,7 +37025,7 @@ SLES-00445:
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Fox Interactive / Electronic Arts"
|
publisher: "Fox Interactive / Electronic Arts"
|
||||||
developer: "Probe Entertainment Limited"
|
developer: "Probe Entertainment Limited"
|
||||||
|
@ -37050,7 +37050,7 @@ SLPS-00585:
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Electronic Arts Victor"
|
publisher: "Electronic Arts Victor"
|
||||||
developer: "Probe Entertainment Limited"
|
developer: "Probe Entertainment Limited"
|
||||||
|
@ -37073,7 +37073,7 @@ SLUS-00119:
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Fox Interactive"
|
publisher: "Fox Interactive"
|
||||||
developer: "Probe Entertainment Limited"
|
developer: "Probe Entertainment Limited"
|
||||||
|
@ -37095,7 +37095,7 @@ SLES-02746:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
- GunCon
|
- GunCon
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Fox Interactive"
|
publisher: "Fox Interactive"
|
||||||
developer: "N-Space"
|
developer: "N-Space"
|
||||||
|
@ -37117,7 +37117,7 @@ SLES-02747:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
- GunCon
|
- GunCon
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Fox Interactive"
|
publisher: "Fox Interactive"
|
||||||
developer: "N-Space"
|
developer: "N-Space"
|
||||||
|
@ -37139,7 +37139,7 @@ SLES-02748:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
- GunCon
|
- GunCon
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Fox Interactive"
|
publisher: "Fox Interactive"
|
||||||
developer: "N-Space"
|
developer: "N-Space"
|
||||||
|
@ -37161,7 +37161,7 @@ SLES-02749:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
- GunCon
|
- GunCon
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Fox Interactive"
|
publisher: "Fox Interactive"
|
||||||
developer: "N-Space"
|
developer: "N-Space"
|
||||||
|
@ -37183,7 +37183,7 @@ SLUS-01015:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
- GunCon
|
- GunCon
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Fox Interactive"
|
publisher: "Fox Interactive"
|
||||||
developer: "N-Space"
|
developer: "N-Space"
|
||||||
|
@ -48310,7 +48310,7 @@ SLUS-00654:
|
||||||
- AnalogController
|
- AnalogController
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- GunCon
|
- GunCon
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Working Designs"
|
publisher: "Working Designs"
|
||||||
|
@ -63836,7 +63836,7 @@ SCPS-10038:
|
||||||
- AnalogController
|
- AnalogController
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- GunCon
|
- GunCon
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Sony"
|
publisher: "Sony"
|
||||||
|
@ -70483,7 +70483,7 @@ SLPM-86021:
|
||||||
name: "Henry Explorers (Japan)"
|
name: "Henry Explorers (Japan)"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Konami"
|
publisher: "Konami"
|
||||||
developer: "Konami"
|
developer: "Konami"
|
||||||
|
@ -72407,7 +72407,7 @@ SCPS-10016:
|
||||||
name: "Horned Owl (Japan)"
|
name: "Horned Owl (Japan)"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
codes:
|
codes:
|
||||||
- SCPS-10016
|
- SCPS-10016
|
||||||
|
@ -79170,7 +79170,7 @@ SLES-00755:
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- GunCon
|
- GunCon
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Gremlin Graphics"
|
publisher: "Gremlin Graphics"
|
||||||
developer: "Gremlin Graphics"
|
developer: "Gremlin Graphics"
|
||||||
|
@ -79193,7 +79193,7 @@ SLUS-00630:
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- GunCon
|
- GunCon
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Activision"
|
publisher: "Activision"
|
||||||
developer: "Gremlin Graphics"
|
developer: "Gremlin Graphics"
|
||||||
|
@ -89788,7 +89788,7 @@ SLES-00542:
|
||||||
name: "Lethal Enforcers (Europe)"
|
name: "Lethal Enforcers (Europe)"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Konami"
|
publisher: "Konami"
|
||||||
developer: "Konami"
|
developer: "Konami"
|
||||||
|
@ -89807,7 +89807,7 @@ SLPM-86025:
|
||||||
name: "Lethal Enforcers Deluxe Pack (Japan)"
|
name: "Lethal Enforcers Deluxe Pack (Japan)"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Konami"
|
publisher: "Konami"
|
||||||
developer: "Konami"
|
developer: "Konami"
|
||||||
|
@ -89826,7 +89826,7 @@ SLUS-00293:
|
||||||
name: "Lethal Enforcers I & II (USA)"
|
name: "Lethal Enforcers I & II (USA)"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Konami"
|
publisher: "Konami"
|
||||||
developer: "Konami"
|
developer: "Konami"
|
||||||
|
@ -96536,7 +96536,7 @@ SLES-01001:
|
||||||
- AnalogController
|
- AnalogController
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- GunCon
|
- GunCon
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Midway"
|
publisher: "Midway"
|
||||||
developer: "Tantalus Entertainment"
|
developer: "Tantalus Entertainment"
|
||||||
|
@ -96563,7 +96563,7 @@ SLUS-00503:
|
||||||
- AnalogController
|
- AnalogController
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- GunCon
|
- GunCon
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Midway"
|
publisher: "Midway"
|
||||||
developer: "Tantalus Entertainment"
|
developer: "Tantalus Entertainment"
|
||||||
|
@ -99864,7 +99864,7 @@ SLPS-00583:
|
||||||
name: "Mighty Hits (Japan)"
|
name: "Mighty Hits (Japan)"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Altron"
|
publisher: "Altron"
|
||||||
developer: "Altron"
|
developer: "Altron"
|
||||||
|
@ -99885,7 +99885,7 @@ SLES-02244:
|
||||||
- AnalogController
|
- AnalogController
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- GunCon
|
- GunCon
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "JVC"
|
publisher: "JVC"
|
||||||
developer: "Altron"
|
developer: "Altron"
|
||||||
|
@ -99908,7 +99908,7 @@ SLPS-02165:
|
||||||
- AnalogController
|
- AnalogController
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- GunCon
|
- GunCon
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Altron"
|
publisher: "Altron"
|
||||||
developer: "Altron"
|
developer: "Altron"
|
||||||
|
@ -126752,7 +126752,7 @@ SCUS-94408:
|
||||||
name: "Project - Horned Owl (USA)"
|
name: "Project - Horned Owl (USA)"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
- PlayStationMouse
|
- PlayStationMouse
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Sony"
|
publisher: "Sony"
|
||||||
|
@ -143581,7 +143581,7 @@ SCPS-45380:
|
||||||
controllers:
|
controllers:
|
||||||
- AnalogController
|
- AnalogController
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
metadata:
|
metadata:
|
||||||
publisher: "Konami"
|
publisher: "Konami"
|
||||||
developer: "KCET"
|
developer: "KCET"
|
||||||
|
@ -143608,7 +143608,7 @@ SLES-01514:
|
||||||
controllers:
|
controllers:
|
||||||
- AnalogController
|
- AnalogController
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
traits:
|
traits:
|
||||||
- ForceRecompilerICache
|
- ForceRecompilerICache
|
||||||
metadata:
|
metadata:
|
||||||
|
@ -143639,7 +143639,7 @@ SLPM-86192:
|
||||||
controllers:
|
controllers:
|
||||||
- AnalogController
|
- AnalogController
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
traits:
|
traits:
|
||||||
- ForceRecompilerICache
|
- ForceRecompilerICache
|
||||||
metadata:
|
metadata:
|
||||||
|
@ -143663,7 +143663,7 @@ SLPM-86498:
|
||||||
controllers:
|
controllers:
|
||||||
- AnalogController
|
- AnalogController
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
codes:
|
codes:
|
||||||
- SLPM-86498
|
- SLPM-86498
|
||||||
- SLPM-87029
|
- SLPM-87029
|
||||||
|
@ -143690,7 +143690,7 @@ SLUS-00707:
|
||||||
controllers:
|
controllers:
|
||||||
- AnalogController
|
- AnalogController
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
traits:
|
traits:
|
||||||
- ForceRecompilerICache
|
- ForceRecompilerICache
|
||||||
metadata:
|
metadata:
|
||||||
|
@ -153683,7 +153683,7 @@ SLES-00654:
|
||||||
- SLES-10654
|
- SLES-10654
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
settings:
|
settings:
|
||||||
dmaMaxSliceTicks: 200
|
dmaMaxSliceTicks: 200
|
||||||
gpuMaxRunAhead: 1
|
gpuMaxRunAhead: 1
|
||||||
|
@ -153710,7 +153710,7 @@ SLES-10654:
|
||||||
- SLES-10654
|
- SLES-10654
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
settings:
|
settings:
|
||||||
dmaMaxSliceTicks: 200
|
dmaMaxSliceTicks: 200
|
||||||
gpuMaxRunAhead: 1
|
gpuMaxRunAhead: 1
|
||||||
|
@ -153737,7 +153737,7 @@ SLES-00656:
|
||||||
- SLES-10656
|
- SLES-10656
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
settings:
|
settings:
|
||||||
dmaMaxSliceTicks: 200
|
dmaMaxSliceTicks: 200
|
||||||
gpuMaxRunAhead: 1
|
gpuMaxRunAhead: 1
|
||||||
|
@ -153764,7 +153764,7 @@ SLES-10656:
|
||||||
- SLES-10656
|
- SLES-10656
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
settings:
|
settings:
|
||||||
dmaMaxSliceTicks: 200
|
dmaMaxSliceTicks: 200
|
||||||
gpuMaxRunAhead: 1
|
gpuMaxRunAhead: 1
|
||||||
|
@ -153791,7 +153791,7 @@ SLES-00584:
|
||||||
- SLES-10584
|
- SLES-10584
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
settings:
|
settings:
|
||||||
dmaMaxSliceTicks: 200
|
dmaMaxSliceTicks: 200
|
||||||
gpuMaxRunAhead: 1
|
gpuMaxRunAhead: 1
|
||||||
|
@ -153818,7 +153818,7 @@ SLES-10584:
|
||||||
- SLES-10584
|
- SLES-10584
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
settings:
|
settings:
|
||||||
dmaMaxSliceTicks: 200
|
dmaMaxSliceTicks: 200
|
||||||
gpuMaxRunAhead: 1
|
gpuMaxRunAhead: 1
|
||||||
|
@ -153845,7 +153845,7 @@ SLES-00643:
|
||||||
- SLES-10643
|
- SLES-10643
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
settings:
|
settings:
|
||||||
dmaMaxSliceTicks: 200
|
dmaMaxSliceTicks: 200
|
||||||
gpuMaxRunAhead: 1
|
gpuMaxRunAhead: 1
|
||||||
|
@ -153872,7 +153872,7 @@ SLES-10643:
|
||||||
- SLES-10643
|
- SLES-10643
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
settings:
|
settings:
|
||||||
dmaMaxSliceTicks: 200
|
dmaMaxSliceTicks: 200
|
||||||
gpuMaxRunAhead: 1
|
gpuMaxRunAhead: 1
|
||||||
|
@ -153899,7 +153899,7 @@ SLPS-00638:
|
||||||
- SLPS-00639
|
- SLPS-00639
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
settings:
|
settings:
|
||||||
dmaMaxSliceTicks: 200
|
dmaMaxSliceTicks: 200
|
||||||
gpuMaxRunAhead: 1
|
gpuMaxRunAhead: 1
|
||||||
|
@ -153926,7 +153926,7 @@ SLPS-00639:
|
||||||
- SLPS-00639
|
- SLPS-00639
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
settings:
|
settings:
|
||||||
dmaMaxSliceTicks: 200
|
dmaMaxSliceTicks: 200
|
||||||
gpuMaxRunAhead: 1
|
gpuMaxRunAhead: 1
|
||||||
|
@ -153956,7 +153956,7 @@ SLES-00644:
|
||||||
versionTested: "0.1-4423-g32ab7c13"
|
versionTested: "0.1-4423-g32ab7c13"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
settings:
|
settings:
|
||||||
dmaMaxSliceTicks: 200
|
dmaMaxSliceTicks: 200
|
||||||
gpuMaxRunAhead: 1
|
gpuMaxRunAhead: 1
|
||||||
|
@ -153986,7 +153986,7 @@ SLES-10644:
|
||||||
versionTested: "0.1-4423-g32ab7c13"
|
versionTested: "0.1-4423-g32ab7c13"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
settings:
|
settings:
|
||||||
dmaMaxSliceTicks: 200
|
dmaMaxSliceTicks: 200
|
||||||
gpuMaxRunAhead: 1
|
gpuMaxRunAhead: 1
|
||||||
|
@ -154013,7 +154013,7 @@ SLUS-00381:
|
||||||
- SLUS-00386
|
- SLUS-00386
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
settings:
|
settings:
|
||||||
dmaMaxSliceTicks: 200
|
dmaMaxSliceTicks: 200
|
||||||
gpuMaxRunAhead: 1
|
gpuMaxRunAhead: 1
|
||||||
|
@ -154043,7 +154043,7 @@ SLUS-00386:
|
||||||
- SLUS-00386
|
- SLUS-00386
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
- KonamiJustifier
|
- Justifier
|
||||||
settings:
|
settings:
|
||||||
dmaMaxSliceTicks: 200
|
dmaMaxSliceTicks: 200
|
||||||
gpuMaxRunAhead: 1
|
gpuMaxRunAhead: 1
|
||||||
|
|
|
@ -73,6 +73,8 @@ add_library(core
|
||||||
imgui_overlays.h
|
imgui_overlays.h
|
||||||
interrupt_controller.cpp
|
interrupt_controller.cpp
|
||||||
interrupt_controller.h
|
interrupt_controller.h
|
||||||
|
justifier.cpp
|
||||||
|
justifier.h
|
||||||
mdec.cpp
|
mdec.cpp
|
||||||
mdec.h
|
mdec.h
|
||||||
memory_card.cpp
|
memory_card.cpp
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "guncon.h"
|
#include "guncon.h"
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
|
#include "justifier.h"
|
||||||
#include "negcon.h"
|
#include "negcon.h"
|
||||||
#include "negcon_rumble.h"
|
#include "negcon_rumble.h"
|
||||||
#include "playstation_mouse.h"
|
#include "playstation_mouse.h"
|
||||||
|
@ -24,6 +25,7 @@ static const Controller::ControllerInfo s_none_info = {ControllerType::None,
|
||||||
static const Controller::ControllerInfo* s_controller_info[] = {
|
static const Controller::ControllerInfo* s_controller_info[] = {
|
||||||
&s_none_info, &DigitalController::INFO, &AnalogController::INFO, &AnalogJoystick::INFO,
|
&s_none_info, &DigitalController::INFO, &AnalogController::INFO, &AnalogJoystick::INFO,
|
||||||
&NeGcon::INFO, &NeGconRumble::INFO, &GunCon::INFO, &PlayStationMouse::INFO,
|
&NeGcon::INFO, &NeGconRumble::INFO, &GunCon::INFO, &PlayStationMouse::INFO,
|
||||||
|
&Justifier::INFO,
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* Controller::ControllerInfo::GetDisplayName() const
|
const char* Controller::ControllerInfo::GetDisplayName() const
|
||||||
|
@ -100,6 +102,9 @@ std::unique_ptr<Controller> Controller::Create(ControllerType type, u32 index)
|
||||||
case ControllerType::GunCon:
|
case ControllerType::GunCon:
|
||||||
return GunCon::Create(index);
|
return GunCon::Create(index);
|
||||||
|
|
||||||
|
case ControllerType::Justifier:
|
||||||
|
return Justifier::Create(index);
|
||||||
|
|
||||||
case ControllerType::PlayStationMouse:
|
case ControllerType::PlayStationMouse:
|
||||||
return PlayStationMouse::Create(index);
|
return PlayStationMouse::Create(index);
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
<ClCompile Include="hotkeys.cpp" />
|
<ClCompile Include="hotkeys.cpp" />
|
||||||
<ClCompile Include="imgui_overlays.cpp" />
|
<ClCompile Include="imgui_overlays.cpp" />
|
||||||
<ClCompile Include="interrupt_controller.cpp" />
|
<ClCompile Include="interrupt_controller.cpp" />
|
||||||
|
<ClCompile Include="justifier.cpp" />
|
||||||
<ClCompile Include="mdec.cpp" />
|
<ClCompile Include="mdec.cpp" />
|
||||||
<ClCompile Include="memory_card.cpp" />
|
<ClCompile Include="memory_card.cpp" />
|
||||||
<ClCompile Include="memory_card_image.cpp" />
|
<ClCompile Include="memory_card_image.cpp" />
|
||||||
|
@ -138,6 +139,7 @@
|
||||||
<ClInclude Include="imgui_overlays.h" />
|
<ClInclude Include="imgui_overlays.h" />
|
||||||
<ClInclude Include="input_types.h" />
|
<ClInclude Include="input_types.h" />
|
||||||
<ClInclude Include="interrupt_controller.h" />
|
<ClInclude Include="interrupt_controller.h" />
|
||||||
|
<ClInclude Include="justifier.h" />
|
||||||
<ClInclude Include="mdec.h" />
|
<ClInclude Include="mdec.h" />
|
||||||
<ClInclude Include="memory_card.h" />
|
<ClInclude Include="memory_card.h" />
|
||||||
<ClInclude Include="memory_card_image.h" />
|
<ClInclude Include="memory_card_image.h" />
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
<ClCompile Include="cpu_newrec_compiler_aarch64.cpp" />
|
<ClCompile Include="cpu_newrec_compiler_aarch64.cpp" />
|
||||||
<ClCompile Include="cpu_newrec_compiler_riscv64.cpp" />
|
<ClCompile Include="cpu_newrec_compiler_riscv64.cpp" />
|
||||||
<ClCompile Include="cpu_newrec_compiler_aarch32.cpp" />
|
<ClCompile Include="cpu_newrec_compiler_aarch32.cpp" />
|
||||||
|
<ClCompile Include="justifier.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="types.h" />
|
<ClInclude Include="types.h" />
|
||||||
|
@ -138,5 +139,6 @@
|
||||||
<ClInclude Include="cpu_newrec_compiler_riscv64.h" />
|
<ClInclude Include="cpu_newrec_compiler_riscv64.h" />
|
||||||
<ClInclude Include="cpu_newrec_compiler_aarch32.h" />
|
<ClInclude Include="cpu_newrec_compiler_aarch32.h" />
|
||||||
<ClInclude Include="achievements_private.h" />
|
<ClInclude Include="achievements_private.h" />
|
||||||
|
<ClInclude Include="justifier.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -273,7 +273,7 @@ static const Controller::ControllerBindingInfo s_binding_info[] = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
BUTTON("Trigger", TRANSLATE_NOOP("GunCon", "Trigger"), nullptr, GunCon::Binding::Trigger, GenericInputBinding::R2),
|
BUTTON("Trigger", TRANSLATE_NOOP("GunCon", "Trigger"), ICON_PF_CROSS, GunCon::Binding::Trigger, GenericInputBinding::R2),
|
||||||
BUTTON("ShootOffscreen", TRANSLATE_NOOP("GunCon", "Shoot Offscreen"), nullptr, GunCon::Binding::ShootOffscreen, GenericInputBinding::L2),
|
BUTTON("ShootOffscreen", TRANSLATE_NOOP("GunCon", "Shoot Offscreen"), nullptr, GunCon::Binding::ShootOffscreen, GenericInputBinding::L2),
|
||||||
BUTTON("A", TRANSLATE_NOOP("GunCon", "A"), ICON_PF_BUTTON_A, GunCon::Binding::A, GenericInputBinding::Cross),
|
BUTTON("A", TRANSLATE_NOOP("GunCon", "A"), ICON_PF_BUTTON_A, GunCon::Binding::A, GenericInputBinding::Cross),
|
||||||
BUTTON("B", TRANSLATE_NOOP("GunCon", "B"), ICON_PF_BUTTON_B, GunCon::Binding::B, GenericInputBinding::Circle),
|
BUTTON("B", TRANSLATE_NOOP("GunCon", "B"), ICON_PF_BUTTON_B, GunCon::Binding::B, GenericInputBinding::Circle),
|
||||||
|
|
|
@ -0,0 +1,475 @@
|
||||||
|
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||||
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||||
|
|
||||||
|
#include "justifier.h"
|
||||||
|
#include "gpu.h"
|
||||||
|
#include "host.h"
|
||||||
|
#include "interrupt_controller.h"
|
||||||
|
#include "resources.h"
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
|
#include "util/imgui_manager.h"
|
||||||
|
#include "util/input_manager.h"
|
||||||
|
#include "util/state_wrapper.h"
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/log.h"
|
||||||
|
#include "common/path.h"
|
||||||
|
#include "common/string_util.h"
|
||||||
|
|
||||||
|
#include "IconsPromptFont.h"
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
Log_SetChannel(Justifier);
|
||||||
|
|
||||||
|
// #define CHECK_TIMING 1
|
||||||
|
#ifdef CHECK_TIMING
|
||||||
|
static u32 s_irq_current_line;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static constexpr std::array<u8, static_cast<size_t>(Justifier::Binding::ButtonCount)> s_button_indices = {{15, 3, 14}};
|
||||||
|
|
||||||
|
Justifier::Justifier(u32 index) : Controller(index)
|
||||||
|
{
|
||||||
|
m_irq_event = TimingEvents::CreateTimingEvent(
|
||||||
|
"Justifier IRQ", 1, 1, [](void* param, TickCount, TickCount) { static_cast<Justifier*>(param)->IRQEvent(); }, this,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Justifier::~Justifier()
|
||||||
|
{
|
||||||
|
if (!m_cursor_path.empty())
|
||||||
|
{
|
||||||
|
const u32 cursor_index = GetSoftwarePointerIndex();
|
||||||
|
if (cursor_index < InputManager::MAX_SOFTWARE_CURSORS)
|
||||||
|
ImGuiManager::ClearSoftwareCursor(cursor_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ControllerType Justifier::GetType() const
|
||||||
|
{
|
||||||
|
return ControllerType::Justifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Justifier::Reset()
|
||||||
|
{
|
||||||
|
m_transfer_state = TransferState::Idle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Justifier::DoState(StateWrapper& sw, bool apply_input_state)
|
||||||
|
{
|
||||||
|
if (!Controller::DoState(sw, apply_input_state))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
u16 irq_first_line = m_irq_first_line;
|
||||||
|
u16 irq_last_line = m_irq_last_line;
|
||||||
|
u16 irq_tick = m_irq_tick;
|
||||||
|
u16 button_state = m_button_state;
|
||||||
|
bool shoot_offscreen = m_shoot_offscreen;
|
||||||
|
bool position_valid = m_position_valid;
|
||||||
|
|
||||||
|
sw.Do(&irq_first_line);
|
||||||
|
sw.Do(&irq_last_line);
|
||||||
|
sw.Do(&irq_tick);
|
||||||
|
sw.Do(&button_state);
|
||||||
|
sw.Do(&shoot_offscreen);
|
||||||
|
sw.Do(&position_valid);
|
||||||
|
|
||||||
|
if (apply_input_state)
|
||||||
|
{
|
||||||
|
m_irq_first_line = irq_first_line;
|
||||||
|
m_irq_last_line = irq_last_line;
|
||||||
|
m_irq_tick = irq_tick;
|
||||||
|
m_button_state = button_state;
|
||||||
|
m_shoot_offscreen = shoot_offscreen;
|
||||||
|
m_position_valid = position_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw.Do(&m_transfer_state);
|
||||||
|
|
||||||
|
if (sw.IsReading())
|
||||||
|
UpdateIRQEvent();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Justifier::GetBindState(u32 index) const
|
||||||
|
{
|
||||||
|
if (index >= s_button_indices.size())
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
const u32 bit = s_button_indices[index];
|
||||||
|
return static_cast<float>(((m_button_state >> bit) & 1u) ^ 1u);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Justifier::SetBindState(u32 index, float value)
|
||||||
|
{
|
||||||
|
const bool pressed = (value >= 0.5f);
|
||||||
|
if (index == static_cast<u32>(Binding::ShootOffscreen))
|
||||||
|
{
|
||||||
|
if (pressed)
|
||||||
|
m_shoot_offscreen = m_shoot_offscreen ? m_shoot_offscreen : m_offscreen_oob_frames;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (index >= static_cast<u32>(Binding::ButtonCount))
|
||||||
|
{
|
||||||
|
if (index >= static_cast<u32>(Binding::BindingCount) || !m_has_relative_binds)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_relative_pos[index - static_cast<u32>(Binding::RelativeLeft)] != value)
|
||||||
|
{
|
||||||
|
m_relative_pos[index - static_cast<u32>(Binding::RelativeLeft)] = value;
|
||||||
|
UpdateSoftwarePointerPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pressed)
|
||||||
|
m_button_state &= ~(u16(1) << s_button_indices[static_cast<u8>(index)]);
|
||||||
|
else
|
||||||
|
m_button_state |= u16(1) << s_button_indices[static_cast<u8>(index)];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Justifier::IsTriggerPressed() const
|
||||||
|
{
|
||||||
|
return ((m_button_state & (1u << 15)) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Justifier::ResetTransferState()
|
||||||
|
{
|
||||||
|
m_transfer_state = TransferState::Idle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Justifier::Transfer(const u8 data_in, u8* data_out)
|
||||||
|
{
|
||||||
|
static constexpr u16 ID = 0x5A31;
|
||||||
|
|
||||||
|
switch (m_transfer_state)
|
||||||
|
{
|
||||||
|
case TransferState::Idle:
|
||||||
|
{
|
||||||
|
// ack when sent 0x01, send ID for 0x42
|
||||||
|
if (data_in == 0x42)
|
||||||
|
{
|
||||||
|
*data_out = Truncate8(ID);
|
||||||
|
m_transfer_state = TransferState::IDMSB;
|
||||||
|
UpdatePosition();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*data_out = 0xFF;
|
||||||
|
return (data_in == 0x01);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case TransferState::IDMSB:
|
||||||
|
{
|
||||||
|
*data_out = Truncate8(ID >> 8);
|
||||||
|
m_transfer_state = TransferState::ButtonsLSB;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TransferState::ButtonsLSB:
|
||||||
|
{
|
||||||
|
*data_out = Truncate8(m_button_state);
|
||||||
|
m_transfer_state = TransferState::ButtonsMSB;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TransferState::ButtonsMSB:
|
||||||
|
{
|
||||||
|
*data_out = Truncate8(m_button_state >> 8);
|
||||||
|
m_transfer_state = TransferState::Idle;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
UnreachableCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Justifier::UpdatePosition()
|
||||||
|
{
|
||||||
|
if (m_shoot_offscreen > 0)
|
||||||
|
{
|
||||||
|
if (m_shoot_offscreen == m_offscreen_trigger_frames)
|
||||||
|
SetBindState(static_cast<u32>(Binding::Trigger), 1.0f);
|
||||||
|
else if (m_shoot_offscreen == m_offscreen_release_frames)
|
||||||
|
SetBindState(static_cast<u32>(Binding::Trigger), 0.0f);
|
||||||
|
|
||||||
|
m_shoot_offscreen--;
|
||||||
|
m_position_valid = false;
|
||||||
|
UpdateIRQEvent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float display_x, display_y;
|
||||||
|
const auto [window_x, window_y] =
|
||||||
|
(m_has_relative_binds) ? GetAbsolutePositionFromRelativeAxes() : InputManager::GetPointerAbsolutePosition(0);
|
||||||
|
g_gpu->ConvertScreenCoordinatesToDisplayCoordinates(window_x, window_y, &display_x, &display_y);
|
||||||
|
|
||||||
|
// are we within the active display area?
|
||||||
|
u32 tick, line;
|
||||||
|
if (display_x < 0 || display_y < 0 ||
|
||||||
|
!g_gpu->ConvertDisplayCoordinatesToBeamTicksAndLines(display_x, display_y, m_x_scale, &tick, &line) ||
|
||||||
|
m_shoot_offscreen)
|
||||||
|
{
|
||||||
|
Log_DevFmt("Lightgun out of range for window coordinates {:.0f},{:.0f}", window_x, window_y);
|
||||||
|
m_position_valid = false;
|
||||||
|
UpdateIRQEvent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_position_valid = true;
|
||||||
|
|
||||||
|
m_irq_tick = static_cast<u16>(static_cast<TickCount>(tick) +
|
||||||
|
System::ScaleTicksToOverclock(static_cast<TickCount>(m_tick_offset)));
|
||||||
|
m_irq_first_line = static_cast<u16>(std::clamp<s32>(static_cast<s32>(line) + m_first_line_offset,
|
||||||
|
static_cast<s32>(g_gpu->GetCRTCActiveStartLine()),
|
||||||
|
static_cast<s32>(g_gpu->GetCRTCActiveEndLine())));
|
||||||
|
m_irq_last_line = static_cast<u16>(std::clamp<s32>(static_cast<s32>(line) + m_last_line_offset,
|
||||||
|
static_cast<s32>(g_gpu->GetCRTCActiveStartLine()),
|
||||||
|
static_cast<s32>(g_gpu->GetCRTCActiveEndLine())));
|
||||||
|
|
||||||
|
Log_DevFmt("Lightgun window coordinates {},{} -> dpy {},{} -> tick {} line {} [{}-{}]", window_x, window_y, display_x,
|
||||||
|
display_y, tick, line, m_irq_first_line, m_irq_last_line);
|
||||||
|
|
||||||
|
UpdateIRQEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Justifier::UpdateIRQEvent()
|
||||||
|
{
|
||||||
|
// TODO: Avoid deactivate and event sort.
|
||||||
|
m_irq_event->Deactivate();
|
||||||
|
|
||||||
|
if (!m_position_valid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
u32 current_tick, current_line;
|
||||||
|
g_gpu->GetBeamPosition(¤t_tick, ¤t_line);
|
||||||
|
|
||||||
|
u32 target_line;
|
||||||
|
if (current_line < m_irq_first_line || current_line >= m_irq_last_line)
|
||||||
|
target_line = m_irq_first_line;
|
||||||
|
else
|
||||||
|
target_line = current_line + 1;
|
||||||
|
|
||||||
|
const TickCount ticks_until_pos = g_gpu->GetSystemTicksUntilTicksAndLine(m_irq_tick, target_line);
|
||||||
|
Log_DebugFmt("Triggering IRQ in {} ticks @ tick {} line {}", ticks_until_pos, m_irq_tick, target_line);
|
||||||
|
m_irq_event->Schedule(ticks_until_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Justifier::IRQEvent()
|
||||||
|
{
|
||||||
|
#ifdef CHECK_TIMING
|
||||||
|
u32 ticks, line;
|
||||||
|
g_gpu->GetBeamPosition(&ticks, &line);
|
||||||
|
|
||||||
|
const u32 expected_line = (s_irq_current_line == m_irq_last_line) ? m_irq_first_line : (s_irq_current_line + 1);
|
||||||
|
if (line < expected_line)
|
||||||
|
Log_WarningFmt("IRQ event fired {} lines too early", expected_line - line);
|
||||||
|
else if (line > expected_line)
|
||||||
|
Log_WarningFmt("IRQ event fired {} lines too late", line - expected_line);
|
||||||
|
if (ticks < m_irq_tick)
|
||||||
|
Log_WarningFmt("IRQ event fired {} ticks too early", m_irq_tick - ticks);
|
||||||
|
else if (ticks > m_irq_tick)
|
||||||
|
Log_WarningFmt("IRQ event fired {} ticks too late", ticks - m_irq_tick);
|
||||||
|
s_irq_current_line = line;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
InterruptController::SetLineState(InterruptController::IRQ::IRQ10, true);
|
||||||
|
InterruptController::SetLineState(InterruptController::IRQ::IRQ10, false);
|
||||||
|
|
||||||
|
UpdateIRQEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Merge all this crap with guncon
|
||||||
|
|
||||||
|
std::pair<float, float> Justifier::GetAbsolutePositionFromRelativeAxes() const
|
||||||
|
{
|
||||||
|
const float screen_rel_x = (((m_relative_pos[1] > 0.0f) ? m_relative_pos[1] : -m_relative_pos[0]) + 1.0f) * 0.5f;
|
||||||
|
const float screen_rel_y = (((m_relative_pos[3] > 0.0f) ? m_relative_pos[3] : -m_relative_pos[2]) + 1.0f) * 0.5f;
|
||||||
|
return std::make_pair(screen_rel_x * ImGuiManager::GetWindowWidth(), screen_rel_y * ImGuiManager::GetWindowHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Justifier::CanUseSoftwareCursor() const
|
||||||
|
{
|
||||||
|
return (InputManager::MAX_POINTER_DEVICES + m_index) < InputManager::MAX_SOFTWARE_CURSORS;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 Justifier::GetSoftwarePointerIndex() const
|
||||||
|
{
|
||||||
|
return m_has_relative_binds ? (InputManager::MAX_POINTER_DEVICES + m_index) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Justifier::UpdateSoftwarePointerPosition()
|
||||||
|
{
|
||||||
|
if (m_cursor_path.empty() || !CanUseSoftwareCursor())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto& [window_x, window_y] = GetAbsolutePositionFromRelativeAxes();
|
||||||
|
ImGuiManager::SetSoftwareCursorPosition(GetSoftwarePointerIndex(), window_x, window_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Justifier> Justifier::Create(u32 index)
|
||||||
|
{
|
||||||
|
return std::make_unique<Justifier>(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Controller::ControllerBindingInfo s_binding_info[] = {
|
||||||
|
#define BUTTON(name, display_name, icon_name, binding, genb) \
|
||||||
|
{ \
|
||||||
|
name, display_name, icon_name, static_cast<u32>(binding), InputBindingInfo::Type::Button, genb \
|
||||||
|
}
|
||||||
|
#define HALFAXIS(name, display_name, icon_name, binding, genb) \
|
||||||
|
{ \
|
||||||
|
name, display_name, icon_name, static_cast<u32>(binding), InputBindingInfo::Type::HalfAxis, genb \
|
||||||
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
BUTTON("Trigger", TRANSLATE_NOOP("Justifier", "Trigger"), ICON_PF_CROSS, Justifier::Binding::Trigger, GenericInputBinding::R2),
|
||||||
|
BUTTON("ShootOffscreen", TRANSLATE_NOOP("Justifier", "Shoot Offscreen"), nullptr, Justifier::Binding::ShootOffscreen, GenericInputBinding::L2),
|
||||||
|
BUTTON("Start", TRANSLATE_NOOP("Justifier", "Start"), ICON_PF_START, Justifier::Binding::Start, GenericInputBinding::Cross),
|
||||||
|
BUTTON("Back", TRANSLATE_NOOP("Justifier", "Back"), ICON_PF_BACK, Justifier::Binding::Back, GenericInputBinding::Circle),
|
||||||
|
|
||||||
|
HALFAXIS("RelativeLeft", TRANSLATE_NOOP("Justifier", "Relative Left"), ICON_PF_ANALOG_LEFT, Justifier::Binding::RelativeLeft, GenericInputBinding::Unknown),
|
||||||
|
HALFAXIS("RelativeRight", TRANSLATE_NOOP("Justifier", "Relative Right"), ICON_PF_ANALOG_RIGHT, Justifier::Binding::RelativeRight, GenericInputBinding::Unknown),
|
||||||
|
HALFAXIS("RelativeUp", TRANSLATE_NOOP("Justifier", "Relative Up"), ICON_PF_ANALOG_UP, Justifier::Binding::RelativeUp, GenericInputBinding::Unknown),
|
||||||
|
HALFAXIS("RelativeDown", TRANSLATE_NOOP("Justifier", "Relative Down"), ICON_PF_ANALOG_DOWN, Justifier::Binding::RelativeDown, GenericInputBinding::Unknown),
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#undef BUTTON
|
||||||
|
};
|
||||||
|
|
||||||
|
static const SettingInfo s_settings[] = {
|
||||||
|
{SettingInfo::Type::Path, "CrosshairImagePath", TRANSLATE_NOOP("Justifier", "Crosshair Image Path"),
|
||||||
|
TRANSLATE_NOOP("Justifier", "Path to an image to use as a crosshair/cursor."), nullptr, nullptr, nullptr, nullptr,
|
||||||
|
nullptr, nullptr, 0.0f},
|
||||||
|
{SettingInfo::Type::Float, "CrosshairScale", TRANSLATE_NOOP("Justifier", "Crosshair Image Scale"),
|
||||||
|
TRANSLATE_NOOP("Justifier", "Scale of crosshair image on screen."), "1.0", "0.0001", "100.0", "0.10", "%.0f%%",
|
||||||
|
nullptr, 100.0f},
|
||||||
|
{SettingInfo::Type::String, "CrosshairColor", TRANSLATE_NOOP("Justifier", "Cursor Color"),
|
||||||
|
TRANSLATE_NOOP("Justifier",
|
||||||
|
"Applies a color to the chosen crosshair images, can be used for multiple players. Specify "
|
||||||
|
"in HTML/CSS format (e.g. #aabbcc)"),
|
||||||
|
"#ffffff", nullptr, nullptr, nullptr, nullptr, nullptr, 0.0f},
|
||||||
|
{SettingInfo::Type::Float, "XScale", TRANSLATE_NOOP("Justifier", "X Scale"),
|
||||||
|
TRANSLATE_NOOP("Justifier", "Scales X coordinates relative to the center of the screen."), "1.0", "0.01", "2.0",
|
||||||
|
"0.01", "%.0f%%", nullptr, 100.0f},
|
||||||
|
{SettingInfo::Type::Integer, "FirstLineOffset", TRANSLATE_NOOP("Justifier", "Line Start Offset"),
|
||||||
|
TRANSLATE_NOOP("Justifier",
|
||||||
|
"Offset applied to lightgun vertical position that the Justifier will first trigger on."),
|
||||||
|
"-14", "-128", "127", "1", "%u"},
|
||||||
|
{SettingInfo::Type::Integer, "LastLineOffset", TRANSLATE_NOOP("Justifier", "Line End Offset"),
|
||||||
|
TRANSLATE_NOOP("Justifier", "Offset applied to lightgun vertical position that the Justifier will last trigger on."),
|
||||||
|
"-8", "-128", "127", "1", "%u"},
|
||||||
|
{SettingInfo::Type::Integer, "TickOffset", TRANSLATE_NOOP("Justifier", "Tick Offset"),
|
||||||
|
TRANSLATE_NOOP("Justifier", "Offset applied to lightgun horizontal position that the Justifier will trigger on."),
|
||||||
|
"50", "-1000", "1000", "1", "%u"},
|
||||||
|
{SettingInfo::Type::Integer, "OffscreenOOBFrames", TRANSLATE_NOOP("Justifier", "Off-Screen Out-Of-Bounds Frames"),
|
||||||
|
TRANSLATE_NOOP("Justifier", "Number of frames that the Justifier is pointed out-of-bounds for an off-screen shot."),
|
||||||
|
"5", "0", "80", "1", "%u"},
|
||||||
|
{SettingInfo::Type::Integer, "OffscreenTriggerFrames", TRANSLATE_NOOP("Justifier", "Off-Screen Trigger Frames"),
|
||||||
|
TRANSLATE_NOOP("Justifier", "Number of frames that the trigger is held for an off-screen shot."), "5", "0", "80",
|
||||||
|
"1", "%u"},
|
||||||
|
{SettingInfo::Type::Integer, "OffscreenReleaseFrames", TRANSLATE_NOOP("Justifier", "Off-Screen Trigger Frames"),
|
||||||
|
TRANSLATE_NOOP("Justifier", "Number of frames that the Justifier is pointed out-of-bounds after the trigger is "
|
||||||
|
"released, for an off-screen shot."),
|
||||||
|
"5", "0", "80", "1", "%u"},
|
||||||
|
};
|
||||||
|
|
||||||
|
const Controller::ControllerInfo Justifier::INFO = {ControllerType::Justifier,
|
||||||
|
"Justifier",
|
||||||
|
TRANSLATE_NOOP("ControllerType", "Justifier"),
|
||||||
|
nullptr,
|
||||||
|
s_binding_info,
|
||||||
|
s_settings,
|
||||||
|
Controller::VibrationCapabilities::NoVibration};
|
||||||
|
|
||||||
|
void Justifier::LoadSettings(SettingsInterface& si, const char* section)
|
||||||
|
{
|
||||||
|
Controller::LoadSettings(si, section);
|
||||||
|
|
||||||
|
m_x_scale = si.GetFloatValue(section, "XScale", 1.0f);
|
||||||
|
|
||||||
|
std::string cursor_path = si.GetStringValue(section, "CrosshairImagePath");
|
||||||
|
const float cursor_scale = si.GetFloatValue(section, "CrosshairScale", 1.0f);
|
||||||
|
u32 cursor_color = 0xFFFFFF;
|
||||||
|
if (std::string cursor_color_str = si.GetStringValue(section, "CrosshairColor", ""); !cursor_color_str.empty())
|
||||||
|
{
|
||||||
|
// Strip the leading hash, if it's a CSS style colour.
|
||||||
|
const std::optional<u32> cursor_color_opt(StringUtil::FromChars<u32>(
|
||||||
|
cursor_color_str[0] == '#' ? std::string_view(cursor_color_str).substr(1) : std::string_view(cursor_color_str),
|
||||||
|
16));
|
||||||
|
if (cursor_color_opt.has_value())
|
||||||
|
cursor_color = cursor_color_opt.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef __ANDROID__
|
||||||
|
if (cursor_path.empty())
|
||||||
|
cursor_path = Path::Combine(EmuFolders::Resources, "images/crosshair.png");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const s32 prev_pointer_index = GetSoftwarePointerIndex();
|
||||||
|
|
||||||
|
m_has_relative_binds = (si.ContainsValue(section, "RelativeLeft") || si.ContainsValue(section, "RelativeRight") ||
|
||||||
|
si.ContainsValue(section, "RelativeUp") || si.ContainsValue(section, "RelativeDown"));
|
||||||
|
|
||||||
|
const s32 new_pointer_index = GetSoftwarePointerIndex();
|
||||||
|
|
||||||
|
if (prev_pointer_index != new_pointer_index || m_cursor_path != cursor_path || m_cursor_scale != cursor_scale ||
|
||||||
|
m_cursor_color != cursor_color)
|
||||||
|
{
|
||||||
|
if (prev_pointer_index != new_pointer_index &&
|
||||||
|
static_cast<u32>(prev_pointer_index) < InputManager::MAX_SOFTWARE_CURSORS)
|
||||||
|
{
|
||||||
|
ImGuiManager::ClearSoftwareCursor(prev_pointer_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointer changed, so need to update software cursor.
|
||||||
|
const bool had_software_cursor = m_cursor_path.empty();
|
||||||
|
m_cursor_path = std::move(cursor_path);
|
||||||
|
m_cursor_scale = cursor_scale;
|
||||||
|
m_cursor_color = cursor_color;
|
||||||
|
if (static_cast<u32>(new_pointer_index) < InputManager::MAX_SOFTWARE_CURSORS)
|
||||||
|
{
|
||||||
|
if (!m_cursor_path.empty())
|
||||||
|
{
|
||||||
|
ImGuiManager::SetSoftwareCursor(new_pointer_index, m_cursor_path, m_cursor_scale, m_cursor_color);
|
||||||
|
if (m_has_relative_binds)
|
||||||
|
UpdateSoftwarePointerPosition();
|
||||||
|
}
|
||||||
|
else if (had_software_cursor)
|
||||||
|
{
|
||||||
|
ImGuiManager::ClearSoftwareCursor(new_pointer_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_first_line_offset =
|
||||||
|
static_cast<s8>(std::clamp<int>(si.GetIntValue(section, "FirstLineOffset", DEFAULT_FIRST_LINE_OFFSET),
|
||||||
|
std::numeric_limits<s8>::min(), std::numeric_limits<s8>::max()));
|
||||||
|
m_last_line_offset =
|
||||||
|
static_cast<s8>(std::clamp<int>(si.GetIntValue(section, "LastLineOffset", DEFAULT_LAST_LINE_OFFSET),
|
||||||
|
std::numeric_limits<s8>::min(), std::numeric_limits<s8>::max()));
|
||||||
|
m_tick_offset = static_cast<s16>(std::clamp<int>(si.GetIntValue(section, "TickOffset", DEFAULT_TICK_OFFSET),
|
||||||
|
std::numeric_limits<s16>::min(), std::numeric_limits<s16>::max()));
|
||||||
|
|
||||||
|
const s8 offscreen_oob_frames =
|
||||||
|
static_cast<s8>(std::clamp<int>(si.GetIntValue(section, "OffscreenOOBFrames", DEFAULT_OFFSCREEN_OOB_FRAMES),
|
||||||
|
std::numeric_limits<s8>::min(), std::numeric_limits<s8>::max()));
|
||||||
|
const s8 offscreen_trigger_frames =
|
||||||
|
static_cast<s8>(std::clamp<int>(si.GetIntValue(section, "OffscreenTriggerFrames", DEFAULT_OFFSCREEN_TRIGGER_FRAMES),
|
||||||
|
std::numeric_limits<s8>::min(), std::numeric_limits<s8>::max()));
|
||||||
|
const s8 offscreen_release_frames =
|
||||||
|
static_cast<s8>(std::clamp<int>(si.GetIntValue(section, "OffscreenReleaseFrames", DEFAULT_OFFSCREEN_RELEASE_FRAMES),
|
||||||
|
std::numeric_limits<s8>::min(), std::numeric_limits<s8>::max()));
|
||||||
|
m_offscreen_oob_frames = offscreen_oob_frames + offscreen_trigger_frames + offscreen_release_frames;
|
||||||
|
m_offscreen_trigger_frames = m_offscreen_oob_frames - offscreen_trigger_frames;
|
||||||
|
m_offscreen_release_frames = m_offscreen_trigger_frames - offscreen_release_frames;
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||||
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "controller.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
class TimingEvent;
|
||||||
|
|
||||||
|
class Justifier final : public Controller
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Binding : u8
|
||||||
|
{
|
||||||
|
Trigger = 0,
|
||||||
|
Start = 1,
|
||||||
|
Back = 2,
|
||||||
|
ShootOffscreen = 3,
|
||||||
|
ButtonCount = 4,
|
||||||
|
|
||||||
|
RelativeLeft = 4,
|
||||||
|
RelativeRight = 5,
|
||||||
|
RelativeUp = 6,
|
||||||
|
RelativeDown = 7,
|
||||||
|
BindingCount = 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Controller::ControllerInfo INFO;
|
||||||
|
|
||||||
|
Justifier(u32 index);
|
||||||
|
~Justifier() override;
|
||||||
|
|
||||||
|
static std::unique_ptr<Justifier> Create(u32 index);
|
||||||
|
|
||||||
|
ControllerType GetType() const override;
|
||||||
|
|
||||||
|
void Reset() override;
|
||||||
|
bool DoState(StateWrapper& sw, bool apply_input_state) override;
|
||||||
|
|
||||||
|
void LoadSettings(SettingsInterface& si, const char* section) override;
|
||||||
|
|
||||||
|
float GetBindState(u32 index) const override;
|
||||||
|
void SetBindState(u32 index, float value) override;
|
||||||
|
|
||||||
|
void ResetTransferState() override;
|
||||||
|
bool Transfer(const u8 data_in, u8* data_out) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool IsTriggerPressed() const;
|
||||||
|
void UpdatePosition();
|
||||||
|
void UpdateIRQEvent();
|
||||||
|
void IRQEvent();
|
||||||
|
|
||||||
|
std::pair<float, float> GetAbsolutePositionFromRelativeAxes() const;
|
||||||
|
bool CanUseSoftwareCursor() const;
|
||||||
|
u32 GetSoftwarePointerIndex() const;
|
||||||
|
void UpdateSoftwarePointerPosition();
|
||||||
|
|
||||||
|
enum class TransferState : u8
|
||||||
|
{
|
||||||
|
Idle,
|
||||||
|
IDMSB,
|
||||||
|
ButtonsLSB,
|
||||||
|
ButtonsMSB,
|
||||||
|
XLSB,
|
||||||
|
XMSB,
|
||||||
|
YLSB,
|
||||||
|
YMSB
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr s8 DEFAULT_FIRST_LINE_OFFSET = -12;
|
||||||
|
static constexpr s8 DEFAULT_LAST_LINE_OFFSET = -6;
|
||||||
|
static constexpr s16 DEFAULT_TICK_OFFSET = 50;
|
||||||
|
static constexpr u8 DEFAULT_OFFSCREEN_OOB_FRAMES = 5;
|
||||||
|
static constexpr u8 DEFAULT_OFFSCREEN_TRIGGER_FRAMES = 5;
|
||||||
|
static constexpr u8 DEFAULT_OFFSCREEN_RELEASE_FRAMES = 5;
|
||||||
|
|
||||||
|
std::unique_ptr<TimingEvent> m_irq_event;
|
||||||
|
|
||||||
|
s8 m_first_line_offset = 0;
|
||||||
|
s8 m_last_line_offset = 0;
|
||||||
|
s16 m_tick_offset = 0;
|
||||||
|
|
||||||
|
u8 m_offscreen_oob_frames = 0;
|
||||||
|
u8 m_offscreen_trigger_frames = 0;
|
||||||
|
u8 m_offscreen_release_frames = 0;
|
||||||
|
|
||||||
|
u16 m_irq_first_line = 0;
|
||||||
|
u16 m_irq_last_line = 0;
|
||||||
|
u16 m_irq_tick = 0;
|
||||||
|
|
||||||
|
// buttons are active low
|
||||||
|
u16 m_button_state = UINT16_C(0xFFFF);
|
||||||
|
u8 m_shoot_offscreen = 0;
|
||||||
|
bool m_position_valid = false;
|
||||||
|
|
||||||
|
TransferState m_transfer_state = TransferState::Idle;
|
||||||
|
|
||||||
|
bool m_has_relative_binds = false;
|
||||||
|
float m_relative_pos[4] = {};
|
||||||
|
|
||||||
|
std::string m_cursor_path;
|
||||||
|
float m_cursor_scale = 1.0f;
|
||||||
|
u32 m_cursor_color = 0xFFFFFFFFu;
|
||||||
|
float m_x_scale = 1.0f;
|
||||||
|
};
|
|
@ -195,6 +195,7 @@ enum class ControllerType : u8
|
||||||
PlayStationMouse,
|
PlayStationMouse,
|
||||||
NeGcon,
|
NeGcon,
|
||||||
NeGconRumble,
|
NeGconRumble,
|
||||||
|
Justifier,
|
||||||
Count
|
Count
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -575,11 +575,12 @@ bool ImGuiManager::AddIconFonts(float size)
|
||||||
0xf5aa, 0xf5aa, 0xf5e7, 0xf5e7, 0xf65d, 0xf65e, 0xf6a9, 0xf6a9, 0xf6cf, 0xf6cf, 0xf70c, 0xf70c, 0xf794, 0xf794,
|
0xf5aa, 0xf5aa, 0xf5e7, 0xf5e7, 0xf65d, 0xf65e, 0xf6a9, 0xf6a9, 0xf6cf, 0xf6cf, 0xf70c, 0xf70c, 0xf794, 0xf794,
|
||||||
0xf7a0, 0xf7a0, 0xf7c2, 0xf7c2, 0xf807, 0xf807, 0xf815, 0xf815, 0xf818, 0xf818, 0xf84c, 0xf84c, 0xf8cc, 0xf8cc,
|
0xf7a0, 0xf7a0, 0xf7c2, 0xf7c2, 0xf807, 0xf807, 0xf815, 0xf815, 0xf818, 0xf818, 0xf84c, 0xf84c, 0xf8cc, 0xf8cc,
|
||||||
0x0, 0x0};
|
0x0, 0x0};
|
||||||
static constexpr ImWchar range_pf[] = {
|
static constexpr ImWchar range_pf[] = {0x2196, 0x2199, 0x219e, 0x21a1, 0x21b0, 0x21b3, 0x21ba, 0x21c3, 0x21c7, 0x21ca,
|
||||||
0x2196, 0x2199, 0x219e, 0x21a1, 0x21b0, 0x21b3, 0x21ba, 0x21c3, 0x21c7, 0x21ca, 0x21d0, 0x21d4, 0x21dc, 0x21dd,
|
0x21d0, 0x21d4, 0x21dc, 0x21dd, 0x21e0, 0x21e3, 0x21ed, 0x21ee, 0x21f7, 0x21f8,
|
||||||
0x21e0, 0x21e3, 0x21ed, 0x21ee, 0x21f7, 0x21f8, 0x21fa, 0x21fb, 0x227a, 0x227f, 0x2284, 0x2284, 0x235e, 0x235e,
|
0x21fa, 0x21fb, 0x227a, 0x227f, 0x2284, 0x2284, 0x235e, 0x235e, 0x2360, 0x2361,
|
||||||
0x2360, 0x2361, 0x2364, 0x2366, 0x23b2, 0x23b4, 0x23f4, 0x23f7, 0x2427, 0x243a, 0x243c, 0x243e, 0x2460, 0x246b,
|
0x2364, 0x2366, 0x23b2, 0x23b4, 0x23ce, 0x23ce, 0x23f4, 0x23f7, 0x2427, 0x243a,
|
||||||
0x24f5, 0x24fd, 0x24ff, 0x24ff, 0x278a, 0x278e, 0x27fc, 0x27fc, 0xe001, 0xe001, 0xff21, 0xff3a, 0x0, 0x0};
|
0x243c, 0x243e, 0x2460, 0x246b, 0x24f5, 0x24fd, 0x24ff, 0x24ff, 0x2717, 0x2717,
|
||||||
|
0x278a, 0x278e, 0x27fc, 0x27fc, 0xe001, 0xe001, 0xff21, 0xff3a, 0x0, 0x0};
|
||||||
|
|
||||||
{
|
{
|
||||||
ImFontConfig cfg;
|
ImFontConfig cfg;
|
||||||
|
|
Loading…
Reference in New Issue