BowlingApplyBallMass3D PROC uses esi mov esi,bpLane3D mov eax,bpWeightKg3D cmp bwTurn3D[esi*4],0 je @F mov eax,bpBotWeightKg3D @@: cmp eax,4 jae @F mov eax,4 @@: cmp eax,7 jbe @F mov eax,7 @@: mov bpShotWeightKg3D,eax imul eax,1000 mov bpBallGrams3D,eax mov ecx,eax mov eax,BP_PIN_GRAMS*FP_1 xor edx,edx div ecx mov bpInvMass3D[BP_BALL_BODY*4],eax ret BowlingApplyBallMass3D ENDP ; Selection consumes its own event, never the direction-lock/throw event. HandleBowlingWeight3D PROC uses ebx esi mousePress:DWORD xor esi,esi bp_weight_key: lea eax,[esi+31h] invoke Pressed3D,eax test eax,eax jnz bp_weight_choose inc esi cmp esi,4 jb bp_weight_key cmp mousePress,0 je bp_weight_no cmp bpState3D,BP_SELECT_BALL je bp_weight_rack_hit cmp mouseY3D,26 jb bp_weight_no cmp mouseY3D,44 jae bp_weight_no cmp mouseX3D,8 jb bp_weight_no cmp mouseX3D,96 jae bp_weight_no mov bpState3D,BP_SELECT_BALL mov eax,1 ret bp_weight_rack_hit: call BowlingRackCamera3D call UpdateCamera3D xor esi,esi bp_weight_hit: invoke BowlingRackScreen3D,esi mov eax,mouseX3D sub eax,bpRackHitX3D[esi*4] imul eax,eax mov ebx,eax mov eax,mouseY3D sub eax,bpRackHitY3D[esi*4] imul eax,eax add ebx,eax mov eax,bpRackHitRadius3D[esi*4] add eax,2 imul eax,eax cmp ebx,eax jbe bp_weight_choose mov eax,bpRackHitX3D[esi*4] sub eax,18 cmp mouseX3D,eax jb bp_weight_hit_next add eax,36 cmp mouseX3D,eax jae bp_weight_hit_next mov eax,bpRackHitY3D[esi*4] add eax,bpRackHitRadius3D[esi*4] add eax,2 cmp mouseY3D,eax jb bp_weight_hit_next add eax,14 cmp mouseY3D,eax jb bp_weight_choose bp_weight_hit_next: inc esi cmp esi,4 jb bp_weight_hit ; Ignore clicks on the floor instead of accidentally locking the direction. cmp mouseY3D,193 jb bp_weight_rack_consumed cmp mouseY3D,213 jae bp_weight_rack_consumed cmp mouseX3D,128 jb bp_weight_rack_consumed cmp mouseX3D,192 jae bp_weight_rack_consumed mov bpState3D,BP_DIRECTION bp_weight_rack_consumed: mov eax,1 ret bp_weight_no: xor eax,eax ret bp_weight_choose: lea eax,[esi+4] mov bpWeightKg3D,eax mov bpState3D,BP_DIRECTION mov eax,1 ret HandleBowlingWeight3D ENDP DrawBowlingWeight3D PROC uses ebx esi edi local x:DWORD,y:DWORD,edge:DWORD cmp bpScoreOpen3D,0 jne bp_weight_draw_done cmp bpState3D,BP_SELECT_BALL jne bp_weight_locked_label invoke DrawString8x8,120,32,OFFSET bpSelectBallText,00E8D7ADh xor esi,esi bp_weight_rack_label: invoke BowlingRackScreen3D,esi mov eax,bpRackHitX3D[esi*4] sub eax,18 mov x,eax mov eax,bpRackHitY3D[esi*4] add eax,bpRackHitRadius3D[esi*4] add eax,2 mov y,eax mov edge,003C4D53h lea eax,[esi+4] cmp eax,bpWeightKg3D jne @F mov eax,bpBallColors3D[esi*4] mov edge,eax @@: invoke DrawBoxBorder,x,y,36,14,00121B20h,edge,1 mov eax,x add eax,2 mov ebx,y add ebx,3 invoke DrawString8x8,eax,ebx,bpWeightLabels3D[esi*4],00FFFFFFh inc esi cmp esi,4 jb bp_weight_rack_label invoke DrawBoxBorder,128,193,64,20,00121B20h,005BC9BEh,1 invoke DrawString8x8,136,199,OFFSET bpTakeBallText,00FFFFFFh ret bp_weight_locked_label: mov eax,bpShotWeightKg3D cmp bpState3D,BP_DIRECTION je bp_weight_selected_label cmp bpState3D,BP_POWER jne @F bp_weight_selected_label: mov eax,bpWeightKg3D @@: cmp bpState3D,BP_BOT jne @F mov eax,bpBotWeightKg3D @@: mov esi,eax invoke FormatNumber,eax,OFFSET bpText3D invoke AppendCString,OFFSET bpText3D,OFFSET bpKilogramsText sub esi,4 cmp esi,3 ja bp_weight_draw_done mov eax,bpBallColors3D[esi*4] mov edge,eax cmp bpState3D,BP_DIRECTION jne bp_weight_static_label invoke DrawBoxBorder,8,26,88,18,00121B20h,edge,1 invoke DrawString8x8,14,31,OFFSET bpChangeBallText,00E8D7ADh invoke DrawString8x8,50,31,OFFSET bpText3D,00FFFFFFh ret bp_weight_static_label: invoke DrawBox,8,27,5,7,edge invoke DrawString8x8,18,26,OFFSET bpText3D,00E8D7ADh bp_weight_draw_done: ret DrawBowlingWeight3D ENDP BowlingBallMaterial3D PROC kg:DWORD mov eax,kg sub eax,4 cmp eax,3 jbe @F mov eax,2 @@: mov eax,bpBallMaterials3D[eax*4] ret BowlingBallMaterial3D ENDP BowlingRackCamera3D PROC mov eax,bpLane3D shr eax,1 imul eax,FP_1*38/10 add eax,FP_1*585/100 mov playerX,eax mov playerY,FP_1*2583/100 mov playerAngle,256 mov viewEye3D,FP_1*102/100 ret BowlingRackCamera3D ENDP ; Labels and picking share the actual world projection, not guessed UI slots. BowlingRackScreen3D PROC uses ebx esi index:DWORD mov esi,index imul ebx,esi,-FP_1*245/1000 add ebx,FP_1*262/10 mov eax,playerX sub eax,FP_1*135/100 invoke ProjectCityPoint3D,eax,ebx sar eax,1 mov bpRackHitX3D[esi*4],eax mov ebx,edx mov eax,viewEye3D sub eax,FP_1*84/100 imul eax,SCREEN_H cdq idiv ebx add eax,viewHorizon3D sar eax,1 mov bpRackHitY3D[esi*4],eax mov eax,FP_1*12/100*SCREEN_H cdq idiv ebx shr eax,1 mov bpRackHitRadius3D[esi*4],eax ret BowlingRackScreen3D ENDP RenderBowlingBallRack3D PROC uses ebx esi edi centre:DWORD,pairIndex:DWORD local lo:DWORD,hi:DWORD,x:DWORD,y:DWORD ; Storage runs lengthwise, alongside (not across) the clear return track. mov eax,centre add eax,FP_1*43/100 mov lo,eax add eax,FP_1*4/100 mov hi,eax invoke DrawRoofSolid3D,lo,hi,FP_1*253/10,FP_1*264/10,FP_1*70/100,FP_1*75/100,238 add lo,FP_1*20/100 add hi,FP_1*20/100 invoke DrawRoofSolid3D,lo,hi,FP_1*253/10,FP_1*264/10,FP_1*70/100,FP_1*75/100,238 mov eax,centre add eax,FP_1*35/100 mov lo,eax add eax,FP_1*40/100 mov hi,eax invoke DrawRoofSolid3D,lo,hi,FP_1*253/10,FP_1*2538/100,FP_1*6/100,FP_1*73/100,254 invoke DrawRoofSolid3D,lo,hi,FP_1*2632/100,FP_1*264/10,FP_1*6/100,FP_1*73/100,254 xor esi,esi bp_rack_stock: cmp bpActive3D,0 je bp_rack_stock_draw mov eax,bpLane3D shr eax,1 cmp eax,pairIndex jne bp_rack_stock_draw cmp bpState3D,BP_SELECT_BALL je bp_rack_stock_draw mov eax,bpWeightKg3D cmp bpState3D,BP_DIRECTION je @F cmp bpState3D,BP_POWER je @F mov eax,bpShotWeightKg3D @@: sub eax,4 cmp eax,esi je bp_rack_stock_next bp_rack_stock_draw: mov eax,centre add eax,FP_1*55/100 mov x,eax imul eax,esi,-FP_1*245/1000 add eax,FP_1*262/10 mov y,eax invoke DrawBowlingBallAt3D,x,y,FP_1*84/100,bpBallMaterials3D[esi*4],45 bp_rack_stock_next: inc esi cmp esi,4 jb bp_rack_stock ret RenderBowlingBallRack3D ENDP ; Reuse the blue marble's luminance; only its hue changes. Preserve alpha. BowlingTintBallPixel3D PROC uses ebx ecx pixel:DWORD,kg:DWORD mov eax,pixel cmp kg,6 je bp_tint_done mov ebx,eax and ebx,255 mov ecx,eax shr ecx,16 and ecx,255 and eax,0FF00FF00h cmp kg,4 jne @F mov edx,pixel shr edx,8 and edx,255 shl ebx,8 and eax,0FFFF00FFh or eax,ebx or eax,edx shl ecx,16 or eax,ecx ret @@: or eax,ecx cmp kg,5 jne bp_tint_gold mov edx,eax and edx,0000FF00h shr edx,1 and edx,0000FF00h and eax,0FFFF00FFh or eax,edx bp_tint_gold: cmp kg,7 jne @F mov edx,pixel shr edx,8 and edx,255 add edx,ebx shr edx,1 shl edx,8 and eax,0FFFF00FFh or eax,edx @@: shl ebx,16 or eax,ebx bp_tint_done: ret BowlingTintBallPixel3D ENDP ; A cached single-frame scratch pack keeps skin, sleeve and source assets intact. BowlingTintHand3D PROC uses ebx esi edi frame:DWORD,kg:DWORD mov eax,frame cmp eax,bpRackHandFrame3D jne bp_tint_hand_build mov eax,kg cmp eax,bpRackHandKg3D je bp_tint_hand_done bp_tint_hand_build: mov eax,frame mov bpRackHandFrame3D,eax shl eax,18 add eax,bpHandArt3D.pixels mov esi,eax mov eax,kg mov bpRackHandKg3D,eax lea edi,bpTintedHandPixels3D mov ebx,256*256 bp_tint_hand_pixel: lodsd cmp kg,6 je bp_tint_hand_store mov edx,eax and edx,255 mov ecx,eax shr ecx,8 and ecx,255 add ecx,24 cmp edx,ecx jbe bp_tint_hand_store mov ecx,eax shr ecx,16 and ecx,255 add ecx,24 cmp edx,ecx jbe bp_tint_hand_store invoke BowlingTintBallPixel3D,eax,kg bp_tint_hand_store: stosd dec ebx jnz bp_tint_hand_pixel mov bpTintedHand3D.imageWidth,256 mov bpTintedHand3D.height,256 mov bpTintedHand3D.frames,1 mov bpTintedHand3D.bytes,256*256*4 mov bpTintedHand3D.pixels,OFFSET bpTintedHandPixels3D bp_tint_hand_done: ret BowlingTintHand3D ENDP