@@ -2479,6 +2479,34 @@ export default function TerminalCanvas({
24792479 return bestIndex >= 0 ? { index : bestIndex , dist : bestDist } : null ;
24802480 } , [ ] ) ;
24812481
2482+ const findNearestDoomPickupInFront = useCallback (
2483+ ( radius : number , halfFov : number ) => {
2484+ const player = doomPlayerRef . current ;
2485+ let bestIndex = - 1 ;
2486+ let bestDist = radius ;
2487+ doomPickupsRef . current . forEach ( ( pickup , index ) => {
2488+ const dx = pickup . x - player . x ;
2489+ const dy = pickup . y - player . y ;
2490+ const dist = Math . hypot ( dx , dy ) ;
2491+ if ( dist >= bestDist ) {
2492+ return ;
2493+ }
2494+ const angle = Math . atan2 ( dy , dx ) ;
2495+ const delta = Math . atan2 (
2496+ Math . sin ( angle - player . angle ) ,
2497+ Math . cos ( angle - player . angle ) ,
2498+ ) ;
2499+ if ( Math . abs ( delta ) > halfFov ) {
2500+ return ;
2501+ }
2502+ bestDist = dist ;
2503+ bestIndex = index ;
2504+ } ) ;
2505+ return bestIndex >= 0 ? { index : bestIndex , dist : bestDist } : null ;
2506+ } ,
2507+ [ ] ,
2508+ ) ;
2509+
24822510 const applyDoomPlayerDamage = useCallback (
24832511 ( damage : number , flash = 2 ) => {
24842512 if ( doomShieldRef . current > 0 ) {
@@ -2929,6 +2957,44 @@ export default function TerminalCanvas({
29292957 } , [ doomText ] ) ;
29302958
29312959 const interactDoom = useCallback ( ( ) => {
2960+ if ( doomGameOverRef . current ) {
2961+ return false ;
2962+ }
2963+
2964+ const player = doomPlayerRef . current ;
2965+ const exit = doomExitRef . current ;
2966+ if ( exit && Math . hypot ( exit . x - player . x , exit . y - player . y ) < 1.05 ) {
2967+ const nextLevel = doomLevelRef . current + 1 ;
2968+ if ( nextLevel < doomLevels . length ) {
2969+ doomAmmoRef . current = Math . min ( 99 , doomAmmoRef . current + 8 ) ;
2970+ doomHealthRef . current = Math . min ( 100 , doomHealthRef . current + 10 ) ;
2971+ loadDoomLevel ( nextLevel , false ) ;
2972+ } else {
2973+ doomMessageRef . current = doomText ( "clear" ) ;
2974+ }
2975+ return true ;
2976+ }
2977+
2978+ const pickupTarget = findNearestDoomPickupInFront ( 1.05 , 0.55 ) ;
2979+ if ( pickupTarget ) {
2980+ const pickup = doomPickupsRef . current [ pickupTarget . index ] ;
2981+ if ( pickup ) {
2982+ const angle = Math . atan2 ( pickup . y - player . y , pickup . x - player . x ) ;
2983+ const wallDist = castDoomDistance (
2984+ player ,
2985+ angle ,
2986+ pickupTarget . dist + 0.12 ,
2987+ ) ;
2988+ if ( wallDist + 0.05 >= pickupTarget . dist ) {
2989+ applyDoomPickup ( pickup ) ;
2990+ doomPickupsRef . current = doomPickupsRef . current . filter (
2991+ ( _ , index ) => index !== pickupTarget . index ,
2992+ ) ;
2993+ return true ;
2994+ }
2995+ }
2996+ }
2997+
29322998 if ( openDoomDoor ( ) ) {
29332999 return true ;
29343000 }
@@ -2945,7 +3011,16 @@ export default function TerminalCanvas({
29453011 ( _ , index ) => index !== nearest . index ,
29463012 ) ;
29473013 return true ;
2948- } , [ applyDoomPickup , findNearestDoomPickup , openDoomDoor ] ) ;
3014+ } , [
3015+ applyDoomPickup ,
3016+ castDoomDistance ,
3017+ doomLevels . length ,
3018+ doomText ,
3019+ findNearestDoomPickup ,
3020+ findNearestDoomPickupInFront ,
3021+ loadDoomLevel ,
3022+ openDoomDoor ,
3023+ ] ) ;
29493024
29503025 const stepDoom = useCallback ( ( ) => {
29513026 const map = doomMapRef . current ;
@@ -3049,7 +3124,7 @@ export default function TerminalCanvas({
30493124 door . open = clamp ( next , 0 , 1 ) ;
30503125 } ) ;
30513126
3052- const autoPickup = findNearestDoomPickup ( 0.45 ) ;
3127+ const autoPickup = findNearestDoomPickup ( 0.6 ) ;
30533128 if ( autoPickup ) {
30543129 const pickup = doomPickupsRef . current [ autoPickup . index ] ;
30553130 if ( pickup ) {
@@ -3061,7 +3136,7 @@ export default function TerminalCanvas({
30613136 }
30623137
30633138 const pickups = doomPickupsRef . current ;
3064- const nearestPickup = findNearestDoomPickup ( 1.15 ) ;
3139+ const nearestPickup = findNearestDoomPickupInFront ( 1.15 , 0.6 ) ;
30653140 let hint : string | null = null ;
30663141 if ( nearestPickup ) {
30673142 const pickup = pickups [ nearestPickup . index ] ;
@@ -3094,22 +3169,10 @@ export default function TerminalCanvas({
30943169 exit &&
30953170 Math . hypot ( exit . x - player . x , exit . y - player . y ) < 1.1
30963171 ) {
3097- hint = doomText ( "exitReady " ) ;
3172+ hint = doomText ( "interactExit " ) ;
30983173 }
30993174 doomHintRef . current = hint ;
31003175
3101- if ( exit && Math . hypot ( exit . x - player . x , exit . y - player . y ) < 0.6 ) {
3102- const nextLevel = doomLevelRef . current + 1 ;
3103- if ( nextLevel < doomLevels . length ) {
3104- doomAmmoRef . current = Math . min ( 99 , doomAmmoRef . current + 8 ) ;
3105- doomHealthRef . current = Math . min ( 100 , doomHealthRef . current + 10 ) ;
3106- loadDoomLevel ( nextLevel , false ) ;
3107- } else {
3108- doomMessageRef . current = doomText ( "clear" ) ;
3109- }
3110- return ;
3111- }
3112-
31133176 const bomb = doomBombRef . current ;
31143177 if ( bomb ?. active ) {
31153178 bomb . x += bomb . vx ;
@@ -3322,11 +3385,10 @@ export default function TerminalCanvas({
33223385 applyDoomPickup ,
33233386 applyDoomPlayerDamage ,
33243387 castDoomDistance ,
3325- doomLevels . length ,
33263388 doomText ,
33273389 findNearestDoomPickup ,
3390+ findNearestDoomPickupInFront ,
33283391 getDoomBootProgress ,
3329- loadDoomLevel ,
33303392 perfTier ,
33313393 triggerDoomExplosion ,
33323394 ] ) ;
@@ -7273,6 +7335,8 @@ export default function TerminalCanvas({
72737335 ctx . fillStyle = "rgba(255,255,255,0.05)" ;
72747336 ctx . fillRect ( pad + 1 , textAreaY - 4 , boxW - 2 , 1 ) ;
72757337
7338+ const textFont = `${ fontSize } px "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace` ;
7339+ ctx . font = textFont ;
72767340 const charWidth = Math . max ( 6 , Math . ceil ( ctx . measureText ( "M" ) . width ) ) ;
72777341 const visibleLines = Math . max ( 1 , Math . floor ( textAreaH / lineHeight ) ) ;
72787342 const maxLineDigits = String ( state . buffer . length ) . length ;
@@ -7679,14 +7743,22 @@ export default function TerminalCanvas({
76797743 if ( ! textures ) {
76807744 return null ;
76817745 }
7682- const v = ( tileX * 31 + tileY * 17 + ( tileX ^ tileY ) * 13 ) % 3 ;
7683- if ( v === 1 ) {
7684- return textures . tech ;
7746+ const level = doomLevelRef . current ;
7747+ const palette = [ textures . brick , textures . tech , textures . stone ] ;
7748+ const base = palette [ level % palette . length ] ?? textures . brick ;
7749+ const accentA =
7750+ palette [ ( level + 1 ) % palette . length ] ?? textures . tech ;
7751+ const accentB =
7752+ palette [ ( level + 2 ) % palette . length ] ?? textures . stone ;
7753+ const key =
7754+ ( tileX * 11 + tileY * 7 + ( tileX ^ tileY ) * 3 + level * 13 ) % 17 ;
7755+ if ( key === 0 ) {
7756+ return accentA ;
76857757 }
7686- if ( v === 2 ) {
7687- return textures . stone ;
7758+ if ( key === 1 ) {
7759+ return accentB ;
76887760 }
7689- return textures . brick ;
7761+ return base ;
76907762 } ;
76917763 const now =
76927764 typeof performance !== "undefined" ? performance . now ( ) : Date . now ( ) ;
@@ -8277,7 +8349,10 @@ export default function TerminalCanvas({
82778349 : sprite . kind === "bomb"
82788350 ? 0.34
82798351 : 0.48 ;
8280- const spriteH = Math . max ( 10 , Math . floor ( baseH * scale ) ) ;
8352+ const spriteH = Math . min (
8353+ Math . floor ( viewH * 0.78 ) ,
8354+ Math . max ( 10 , Math . floor ( baseH * scale ) ) ,
8355+ ) ;
82818356 const aspect =
82828357 sprite . kind === "pillar"
82838358 ? 0.35
@@ -8380,7 +8455,10 @@ export default function TerminalCanvas({
83808455 : enemy . type === "spitter"
83818456 ? 1.05
83828457 : 0.96 ;
8383- const spriteH = Math . max ( 22 , Math . floor ( baseH * 0.92 * enemyScale ) ) ;
8458+ const spriteH = Math . min (
8459+ Math . floor ( viewH * 0.92 ) ,
8460+ Math . max ( 22 , Math . floor ( baseH * 0.92 * enemyScale ) ) ,
8461+ ) ;
83848462 const spriteW = Math . max (
83858463 18 ,
83868464 Math . floor ( spriteH * ( enemy . type === "brute" ? 0.62 : 0.55 ) ) ,
@@ -8592,9 +8670,12 @@ export default function TerminalCanvas({
85928670 }
85938671 const baseH = Math . min ( viewH , Math . floor ( viewH / dist ) ) ;
85948672 const isRocket = projectile . kind === "rocket" ;
8595- const size = Math . max (
8596- isRocket ? 10 : 8 ,
8597- Math . floor ( baseH * ( isRocket ? 0.22 : 0.16 ) ) ,
8673+ const size = Math . min (
8674+ Math . floor ( viewH * 0.28 ) ,
8675+ Math . max (
8676+ isRocket ? 10 : 8 ,
8677+ Math . floor ( baseH * ( isRocket ? 0.22 : 0.16 ) ) ,
8678+ ) ,
85988679 ) ;
85998680 const top = Math . floor (
86008681 viewY + viewH * 0.48 - size / 2 + cameraBob * 0.2 ,
@@ -8693,7 +8774,10 @@ export default function TerminalCanvas({
86938774 const screenX =
86948775 viewX + ( 0.5 + delta / fov ) * Math . max ( 1 , viewW ) ;
86958776 const spriteH = Math . min ( viewH , Math . floor ( viewH / dist ) ) ;
8696- const size = Math . max ( 6 , Math . floor ( spriteH * 0.15 ) ) ;
8777+ const size = Math . min (
8778+ Math . floor ( viewH * 0.18 ) ,
8779+ Math . max ( 6 , Math . floor ( spriteH * 0.15 ) ) ,
8780+ ) ;
86978781 const top = Math . floor ( viewY + ( viewH - size ) / 2 ) ;
86988782 ctx . fillStyle = "#f4d35e" ;
86998783 ctx . beginPath ( ) ;
@@ -8724,7 +8808,10 @@ export default function TerminalCanvas({
87248808 const screenX =
87258809 viewX + ( 0.5 + delta / fov ) * Math . max ( 1 , viewW ) ;
87268810 const spriteH = Math . min ( viewH , Math . floor ( viewH / dist ) ) ;
8727- const size = Math . max ( 16 , Math . floor ( spriteH * 0.35 ) ) ;
8811+ const size = Math . min (
8812+ Math . floor ( viewH * 0.45 ) ,
8813+ Math . max ( 16 , Math . floor ( spriteH * 0.35 ) ) ,
8814+ ) ;
87288815 const top = Math . floor ( viewY + ( viewH - size ) / 2 ) ;
87298816 ctx . fillStyle = "rgba(246,194,122,0.6)" ;
87308817 ctx . beginPath ( ) ;
0 commit comments