{$CLEO}                      // Improvement of trams traffic  (by Den_spb)
var
    0@: Integer 
    1@: Integer
                   // 2-14    
    15@: Integer
    16@: Integer
    17@: Integer
    18@: Float
    19@: Float
    20@: Integer
    21@: Float
    22@: Integer
    23@: Integer
end
const
    TRAM = 0@
    TRAM_STRUCT = 1@
    FLAGS = 15@
    PASSENGER_0 = 16@
    PASSENGER_1 = 17@
    LAST_0BJECT_X = 18@
    LAST_0BJECT_Y = 19@
    0BJECT = 20@
    Y_DIMENSION = 21@
    MAR_KER = 22@
    STOPS_C0UNT = 23@
                         // BIT FLAGS:
    MANY_CARRIAGES = 0
    AUTODRIVE_OFF = 1
    TRAM_IS_STOPPING = 2
    CJ_IS_PASSENGER = 3
end
TRAM = -1
0A8C: write_memory 0x6F7863 size 2 value 0 virtual_protect 1  //        
LAST_0BJECT_X = 50000.0
LAST_0BJECT_Y = 50000.0
while true
    wait 0
    if or
        not player.Defined($PLAYER_CHAR)
        $ONMISSION <> 0                      
    then
        continue
    end
    if
        856E:   not car TRAM defined     
    then
        if
            8154:   not actor $PLAYER_ACTOR in_zone 'SF'  // San Fierro
        then
            continue
        end
        if      
            gosub @SEARCH_TRAM
        then
            marker.CreateAboveCar(MAR_KER TRAM) 
            07E0: set_marker MAR_KER type_to 1  
            018B: set_marker MAR_KER radar_mode 2   
            FLAGS = 0
            0A97: TRAM_STRUCT = car TRAM struct
            TRAM_STRUCT += 0x5D4
            0A8D: TRAM_STRUCT = read_memory TRAM_STRUCT size 4 virtual_protect 0
            07E4: get_model 449 dimensions_cornerA_to 2@ 3@ 4@ dimensions_cornerB_to 5@ Y_DIMENSION 7@
            if
                TRAM_STRUCT > 0
            then
                Y_DIMENSION += 16.0
                08BD: set FLAGS bit MANY_CARRIAGES
            else
                Y_DIMENSION += 12.0 
            end
            0209: 8@ = random_int_in_ranges 0 2
            if
                8@ == 0
            then
                0561: PASSENGER_0 = create_passenger_in_car TRAM seat 0
                actor.RemoveReferences(PASSENGER_0)
            else 
                0561: PASSENGER_1 = create_passenger_in_car TRAM seat 1
                actor.RemoveReferences(PASSENGER_1)
            end   
        end            
    else                                                                                           // tram defined
        0AB5: store_actor $PLAYER_ACTOR closest_vehicle_to 2@ closest_ped_to 3@
        if and                              //            
            003B:   2@ == TRAM // (int) 
            $ONMISSION == 0
            not actor.Driving($PLAYER_ACTOR) 
        then
            if
                0AB0:  key_pressed 219 //      [
            then
                05CB: AS_actor $PLAYER_ACTOR enter_car TRAM as_driver -1 ms
            else
                if
                    0AB0:  key_pressed 221 //      ]
                then
                    if
                        0431:   car TRAM passenger_seat_free 0 
                    then
                        05CA: AS_actor $PLAYER_ACTOR enter_car TRAM passenger_seat 0 -1 ms 
                    else
                        if
                            0431:   car TRAM passenger_seat_free 1
                        then
                            05CA: AS_actor $PLAYER_ACTOR enter_car TRAM passenger_seat 1 -1 ms
                        end
                    end    
                end
            end
        end      // cj entering tram
        046C: 2@ = car TRAM driver
        if
            856D:  not  actor 2@ defined 
        then
            08BD: set FLAGS bit AUTODRIVE_OFF
            06DD: set_train TRAM speed 0.0
        end        
        if                                    //        
            actor.InCar($PLAYER_ACTOR TRAM)
        then
            if
                003C:   $PLAYER_ACTOR == 2@ // (int) 
            then
                08BD: set FLAGS bit AUTODRIVE_OFF
                06DD: set_train TRAM speed 0.0
            else
                if
                    88B7:   not test FLAGS bit CJ_IS_PASSENGER 
                then
                    08BD: set FLAGS bit CJ_IS_PASSENGER
                    0109: player $PLAYER_CHAR money += -5    
                end 
            end
        else
            08C3: clear FLAGS bit CJ_IS_PASSENGER 
        end        //   cj not in tram
        if
            88B7:   not test FLAGS bit AUTODRIVE_OFF    //  
        then
            if
                88B7:   not test FLAGS bit TRAM_IS_STOPPING   //        
            then
                if
                    gosub @CHECK_OBSTACLES
                then
                    06DD: set_train TRAM speed 0.0
                  {  Car.StorePos(TRAM 2@ 3@ 10@) ///////////////////////////////////////////////////////////////////////////////////////////
                    10@ += 3.0
                    024F: create_corona_with_radius 1.0 type 2 lensflares 0 with_color 255 255 0 at 2@ 3@ 10@ /////////////////////      }
                else
                    Car.StorePos(TRAM 2@ 3@ 10@)
                    0407: store_coords_to 5@ 6@ 4@ from_car TRAM with_offset 0.0 -1.0 0.0 
                    0407: store_coords_to 7@ 8@ 4@ from_car TRAM with_offset 0.0 1.0 0.0
                    0509: 4@ = distance_between_XY LAST_0BJECT_X LAST_0BJECT_Y and_XY 5@ 6@
                    0509: 9@ = distance_between_XY LAST_0BJECT_X LAST_0BJECT_Y and_XY 7@ 8@
                    if
                        0025:   9@ > 4@ // (float) 
                    then
                        0407: store_coords_to LAST_0BJECT_X LAST_0BJECT_Y 4@ from_car TRAM with_offset 0.0 -50000.0 0.0    
                    end 
                    if
                        gosub @SEARCH_OBJECTS
                    then
                        object.StorePos(0BJECT LAST_0BJECT_X LAST_0BJECT_Y 12@)
                        06DD: set_train TRAM speed 0.0
                      {  12@ += 2.0 ///////////////////////////////////////////////////////////////////////////////////////////////////////////
                        024F: create_corona_with_radius 1.0 type 2 lensflares 0 with_color 0 0 255 at LAST_0BJECT_X LAST_0BJECT_Y 12@ /////// }
                    else    
                        06DD: set_train TRAM speed 11.11
                    end                        
                end
            else
                if
                    01C1:   car TRAM stopped 
                then
                    if
                        32@ < -5000
                    then
                        32@ = -5000                       
                        if and
                            0431: car TRAM passenger_seat_free 0
                            0431: car TRAM passenger_seat_free 1
                        then
                            car.StorePos(TRAM 2@ 3@ 4@)
                            if
                                gosub @SEARCH_PASSENGERS
                            then   
                                0209: 8@ = random_int_in_ranges 0 2 
                                if
                                    8@ == 0
                                then
                                    05CA: AS_actor 5@ enter_car TRAM passenger_seat 0 -1 ms 
                                else
                                    05CA: AS_actor 5@ enter_car TRAM passenger_seat 1 -1 ms
                                end
                            end
                        else
                            if
                                STOPS_C0UNT >= 2
                            then
                                0432: PASSENGER_0 = get_actor_handle_from_car TRAM passenger_seat 0
                                if and
                                    056D:   actor PASSENGER_0 defined 
                                    803C:  not  $PLAYER_ACTOR == PASSENGER_0 // (int) 
                                then
                                    0633: AS_actor PASSENGER_0 exit_car   
                                else
                                    0432: PASSENGER_1 = get_actor_handle_from_car TRAM passenger_seat 1
                                    if and
                                        056D:   actor PASSENGER_1 defined 
                                        803C:  not  $PLAYER_ACTOR == PASSENGER_1 // (int) 
                                    then
                                        0633: AS_actor PASSENGER_1 exit_car
                                    end    
                                end
                                STOPS_C0UNT = 0
                            else
                                STOPS_C0UNT += 1 
                            end     
                        end         
                    else
                        if
                            32@ >= 0
                        then
                            08C3: clear FLAGS bit TRAM_IS_STOPPING
                            06DD: set_train TRAM speed 11.11
                        end
                    end
                end
            end    // tram is stopping
        end  // cj is not driver          
    end   // tram defined
end

:SEARCH_TRAM        //  
if
    0AE2: TRAM = random_vehicle_near_point 0.0 0.0 0.0 in_radius 6000.0 find_next 0 pass_wrecked 1 //IF and SET
then
    repeat
        if
            0137:   car TRAM model == 449
        then
            0A97: TRAM_STRUCT = car TRAM struct
            TRAM_STRUCT += 0x5D0
            0A8D: TRAM_STRUCT = read_memory TRAM_STRUCT size 4 virtual_protect 0
            if
                TRAM_STRUCT == 0   //    (   )
            then   
                0485: return_true
                return
            end
        end
    until 8AE2: not TRAM = random_vehicle_near_point 0.0 0.0 0.0 in_radius 6000.0 find_next 1 pass_wrecked 1 //IF and SET
end
TRAM = -1
8485: return_false
return

:CHECK_OBSTACLES       //    
07E4: get_model 449 dimensions_cornerA_to 2@ 3@ 4@ dimensions_cornerB_to 5@ 8@ 7@
2@ -= 0.1
5@ += 0.1
repeat
    0407: store_coords_to 9@ 10@ 11@ from_car TRAM with_offset 2@ 0.0 4@              //1
    0407: store_coords_to 12@ 13@ 14@ from_car TRAM with_offset 2@ Y_DIMENSION 4@
    if
        86BD:   not no_obstacles_between 9@ 10@ 11@ and 12@ 13@ 14@ solid 0 car 1 actor 1 object 0 particle 0 
    then
        0485: return_true
        return
    end
    0407: store_coords_to 9@ 10@ 11@ from_car TRAM with_offset 2@ Y_DIMENSION 4@     //2
    0407: store_coords_to 12@ 13@ 14@ from_car TRAM with_offset 5@ Y_DIMENSION 4@
    if
        86BD:   not no_obstacles_between 9@ 10@ 11@ and 12@ 13@ 14@ solid 0 car 1 actor 1 object 0 particle 0 
    then
        0485: return_true
        return
    end
    0407: store_coords_to 9@ 10@ 11@ from_car TRAM with_offset 5@ 0.0 4@             //3
    0407: store_coords_to 12@ 13@ 14@ from_car TRAM with_offset 5@ Y_DIMENSION 4@
    if
        86BD:   not no_obstacles_between 9@ 10@ 11@ and 12@ 13@ 14@ solid 0 car 1 actor 1 object 0 particle 0 
    then
        0485: return_true
        return
    end
    0407: store_coords_to 9@ 10@ 11@ from_car TRAM with_offset 2@ 8@ 4@               //6
    0407: store_coords_to 12@ 13@ 14@ from_car TRAM with_offset 5@ 8@ 4@
    if
        86BD:   not no_obstacles_between 9@ 10@ 11@ and 12@ 13@ 14@ solid 0 car 1 actor 1 object 0 particle 0 
    then
        0485: return_true
        return
    end
    0087: 3@ = 2@ // (float)
    repeat
        0407: store_coords_to 9@ 10@ 11@ from_car TRAM with_offset 3@ 8@ 4@             //.
        0407: store_coords_to 12@ 13@ 14@ from_car TRAM with_offset 3@ Y_DIMENSION 4@
        if
            86BD:   not no_obstacles_between 9@ 10@ 11@ and 12@ 13@ 14@ solid 0 car 1 actor 1 object 0 particle 0 
        then
            0485: return_true
            return
        end               
        3@ += 0.4 //   0.2
    until 0025:   3@ > 5@ // (float)            
    4@ += 1.0  //    0.5
until 0025:   4@ > 7@ // (float)
8485: return_false 
return

:SEARCH_PASSENGERS    //  ,    
if
    0AE1: 5@ = random_actor_near_point 2@ 3@ 4@ in_radius 20.0 find_next 0 pass_deads 1 //IF and SET
then
    repeat
        089F: get_actor 5@ pedtype_to 6@ 
        if or
            6@ == 4
            6@ == 5
        then
            080E: get_actor 5@ ped_event_to 6@
            if and
                6@ == 13
                803B: not 5@ == $PLAYER_ACTOR // (int) 
            then
                0485: return_true
                return
            end
        end
    until 8AE1: not 5@ = random_actor_near_point 2@ 3@ 4@ in_radius 20.0 find_next 1 pass_deads 1 //IF and SET
end
8485: return_false
return

:SEARCH_OBJECTS   //          
if
    0AE3: 0BJECT = random_object_near_point 2@ 3@ 10@ in_radius Y_DIMENSION find_next 0
then
    repeat
        if and       //   
            89CC: not object 0BJECT model_is 3855  //   GAY_TRAFFIC_LIGHT      +
            89CC: not object 0BJECT model_is 1315  //   TRAFFICLIGHT1          +
            89CC: not object 0BJECT model_is 1352  //   CJ_TRAFFIC_LIGHT3      +
            89CC: not object 0BJECT model_is 1350  //   CJ_TRAFFIC_LIGHT4      +
            89CC: not object 0BJECT model_is 1351  //   CJ_TRAFFIC_LIGHT5      +
            89CC: not object 0BJECT model_is 3516  //      VGSSTRIPTLIGHTS1    +
            89CC: not object 0BJECT model_is 1283  //       MTRAFFIC1          +
        then
            if and
                89CC: not object 0BJECT model_is 1284   //      MTRAFFIC2      +
                89CC: not object 0BJECT model_is 1375   //    TRAMSTOP_SF      +                
            then
                continue
            end
        end                                 
        object.StorePos(0BJECT 4@ 9@ 12@)
        12@ += 1.0
        0509: 14@ = distance_between_XY 2@ 3@ and_XY 4@ 9@ 
        0509: 13@ = distance_between_XY 2@ 3@ and_XY LAST_0BJECT_X LAST_0BJECT_Y        
        if or    //       ,            
            0025:   14@ > 13@ // (float)
            86BD:   not no_obstacles_between 2@ 3@ 10@ and 4@ 9@ 12@ solid 1 car 0 actor 0 object 0 particle 0  
        then
            continue
        end     
        0509: 12@ = distance_between_XY 4@ 9@ and_XY 5@ 6@ 
        0509: 13@ = distance_between_XY 4@ 9@ and_XY 7@ 8@
        if          //      
            0035:   13@ >= 12@ // (float) 
        then
            continue
        end
        if         //      (  )
            09CC: object 0BJECT model_is 1375   //    TRAMSTOP_SF      + 
        then
            if and
                8045: not  4@ == LAST_0BJECT_X // (float) 
                8045: not  9@ == LAST_0BJECT_Y // (float) 
            then
                32@ = -900000
                08BD: set FLAGS bit TRAM_IS_STOPPING
                0485: return_true
                return
            end    
        else    //   
            0174: 6@ = car TRAM Z_angle  //////////////////////////////////////////////////////////////////////////////////////////////////
            0176: 8@ = object 0BJECT Z_angle 
            0063: 8@ -= 6@ // (float)
            0656: get_angle 8@ absolute_degrees_to 8@
            if
                gosub @CHECK_TRAFFICLIGHT_ANGLE
            then
                0176: 8@ = object 0BJECT Z_angle
                if and
                    8@ >= 60.0
                    8@ <= 150.0
                then
                    0AA7: call_function 0x49D3A0 num_params 0 pop 0 9@ //   2   WE
                else
                    if and
                        8@ >= 240.0
                        8@ <= 330.0
                    then
                        0AA7: call_function 0x49D3A0 num_params 0 pop 0 9@ //   2   WE
                    else
                        0AA7: call_function 0x49D350 num_params 0 pop 0 9@ //   1   NS
                    end
                end
                for 8@ = 8 to 31
                    08C3: clear 9@ bit 8@
                end  //  : 0 - , 1 - , 2 - 
                if
                    9@ <> 0
                then
                    0485: return_true
                    return
                end            
            end             
        end        
    until  8AE3: not 0BJECT = random_object_near_point 2@ 3@ 10@ in_radius Y_DIMENSION find_next 1
end
8485: return_false
return

:CHECK_TRAFFICLIGHT_ANGLE  // ,     
if or
    8@ > 315.0
    8@ < 45.0
then
    0485: return_true
    return
end
if or
    09CC: object 0BJECT model_is 1283
    09CC: object 0BJECT model_is 1284
then
    if and
        8@ > 135.0
        8@ < 225.0
    then
        0485: return_true
        return
    end
end    
8485: return_false
return