diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj
index cd66b434b3..491574e929 100644
--- a/projects/openrct2.vcxproj
+++ b/projects/openrct2.vcxproj
@@ -300,6 +300,7 @@
{D24D94F6-2A74-480C-B512-629C306CE92F}
openrct2
openrct2
+ 10.0.10240.0
diff --git a/src/common.h b/src/common.h
index 4ea6488767..a965995ce0 100644
--- a/src/common.h
+++ b/src/common.h
@@ -29,7 +29,9 @@
#define SafeDelete(x) if ((x) != nullptr) { delete (x); (x) = nullptr; }
#define SafeDeleteArray(x) if ((x) != nullptr) { delete[] (x); (x) = nullptr; }
-#define interface struct
+#ifndef interface
+ #define interface struct
+#endif
#define abstract = 0
#endif
\ No newline at end of file
diff --git a/src/localisation/string_ids.h b/src/localisation/string_ids.h
index c725353b63..8840ff8ae0 100644
--- a/src/localisation/string_ids.h
+++ b/src/localisation/string_ids.h
@@ -1662,6 +1662,7 @@ enum {
STR_THIS_DESIGN_WILL_BE_BUILT_WITH_AN_ALTERNATIVE_VEHICLE_TYPE = 3136,
STR_SELECT_NEARBY_SCENERY = 3137,
STR_RESET_SELECTION = 3138,
+ STR_CABLE_LIFT_UNABLE_TO_WORK_IN_THIS_OPERATING_MODE = 3139,
STR_MULTICIRCUIT_NOT_POSSIBLE_WITH_CABLE_LIFT_HILL = 3141,
diff --git a/src/network/http.cpp b/src/network/http.cpp
index a2ad158bec..306bde03ed 100644
--- a/src/network/http.cpp
+++ b/src/network/http.cpp
@@ -10,9 +10,12 @@ void http_dispose() { }
#else
#include
-#include
#include
+// cURL includes windows.h, but we don't need all of it.
+#define WIN32_LEAN_AND_MEAN
+#include
+
typedef struct {
char *ptr;
int length;
diff --git a/src/ride/ride.c b/src/ride/ride.c
index dbe9271617..2eb5de507d 100644
--- a/src/ride/ride.c
+++ b/src/ride/ride.c
@@ -4212,22 +4212,103 @@ void ride_set_start_finish_points(int rideIndex, rct_xy_element *startElement)
}
}
+/**
+ *
+ * rct2: 0x0069ED9E
+ */
+static int sub_69ED9E()
+{
+ int miscSpriteCount = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_COUNT_MISC, uint16);
+ int unkCount = RCT2_GLOBAL(0x013573C8, uint16);
+ return max(0, miscSpriteCount + unkCount - 300);
+}
+
/**
*
* rct2: 0x006DD84C
*/
-int sub_6DD84C(rct_ride *ride, int rideIndex, rct_xy_element *element, int isApplying)
+int ride_create_vehicles(rct_ride *ride, int rideIndex, rct_xy_element *element, int isApplying)
{
return RCT2_CALLPROC_X(0x006DD84C, element->x, isApplying, element->y, rideIndex, (int)ride, (int)element->element, 0) & 0x100;
}
+static bool sub_6D31A6(rct_ride *ride)
+{
+ return !(RCT2_CALLPROC_X(0x006D31A6, 0, 0, 0, 0, 0, (int)ride, 0) & 0x100);
+}
+
/**
*
* rct2: 0x006DF4D4
*/
-int sub_6DF4D4(rct_ride *ride, rct_xy_element *element, int isApplying)
+bool ride_create_cable_lift(int rideIndex, bool isApplying)
{
- return RCT2_CALLPROC_X(0x006DF4D4, element->x, isApplying, element->y, 0, (int)ride, (int)element->element, 0) & 0x100;
+ rct_ride *ride = GET_RIDE(rideIndex);
+
+ if (ride->mode != RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED &&
+ ride->mode != RIDE_MODE_CONTINUOUS_CIRCUIT
+ ) {
+ RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CABLE_LIFT_UNABLE_TO_WORK_IN_THIS_OPERATING_MODE;
+ return false;
+ }
+
+ if (ride->num_circuits > 1) {
+ RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_MULTICIRCUIT_NOT_POSSIBLE_WITH_CABLE_LIFT_HILL;
+ return false;
+ }
+
+ if (sub_69ED9E() <= 5) {
+ RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_UNABLE_TO_CREATE_ENOUGH_VEHICLES;
+ return false;
+ }
+
+ if (!sub_6D31A6(ride)) {
+ return false;
+ }
+
+ if (!isApplying) {
+ return true;
+ }
+
+ int x = ride->cable_lift_x;
+ int y = ride->cable_lift_y;
+ int z = ride->cable_lift_z;
+ rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5);
+ do {
+ if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) continue;
+ if (mapElement->base_height != z) continue;
+ break;
+ } while (!map_element_is_last_for_tile(mapElement++));
+ int direction = mapElement->type & MAP_ELEMENT_DIRECTION_MASK;
+
+ rct_vehicle *head = NULL;
+ rct_vehicle *tail = NULL;
+ uint32 ebx = 0;
+ for (int i = 0; i < 5; i++) {
+ uint32 edx = ror32(0x15478, 10);
+ uint16 var_44 = edx & 0xFFFF;
+ edx = rol32(edx, 10) >> 1;
+ ebx -= edx;
+ uint32 var_24 = ebx;
+ ebx -= edx;
+
+ rct_vehicle *current = cable_lift_segment_create(rideIndex, x, y, z, direction, var_44, var_24, i == 0);
+ current->next_vehicle_on_train = SPRITE_INDEX_NULL;
+ if (i == 0) {
+ head = current;
+ } else {
+ tail->next_vehicle_on_train = current->sprite_index;
+ tail->next_or_first_vehicle_on_train = current->sprite_index;
+ current->prev_vehicle_on_train = tail->sprite_index;
+ }
+ tail = current;
+ }
+ head->prev_vehicle_on_train = tail->sprite_index;
+ tail->next_or_first_vehicle_on_train = head->sprite_index;
+
+ ride->lifecycle_flags |= RIDE_LIFECYCLE_CABLE_LIFT;
+ sub_6DEF56(head);
+ return true;
}
/**
@@ -4440,7 +4521,7 @@ int ride_is_valid_for_test(int rideIndex, int goingToBeOpen, int isApplying)
!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_13) &&
!(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)
) {
- if (sub_6DD84C(ride, rideIndex, &trackElement, isApplying))
+ if (ride_create_vehicles(ride, rideIndex, &trackElement, isApplying))
return 0;
}
@@ -4449,7 +4530,7 @@ int ride_is_valid_for_test(int rideIndex, int goingToBeOpen, int isApplying)
(ride->lifecycle_flags & RIDE_LIFECYCLE_16) &&
!(ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT)
) {
- if (sub_6DF4D4(ride, &trackElement, isApplying))
+ if (!ride_create_cable_lift(rideIndex, isApplying))
return 0;
}
@@ -4563,7 +4644,7 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying)
!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_13) &&
!(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)
) {
- if (sub_6DD84C(ride, rideIndex, &trackElement, isApplying))
+ if (ride_create_vehicles(ride, rideIndex, &trackElement, isApplying))
return 0;
}
@@ -4572,7 +4653,7 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying)
(ride->lifecycle_flags & RIDE_LIFECYCLE_16) &&
!(ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT)
) {
- if (sub_6DF4D4(ride, &trackElement, isApplying))
+ if (!ride_create_cable_lift(rideIndex, isApplying))
return 0;
}
diff --git a/src/ride/ride.h b/src/ride/ride.h
index a0135572f6..68c99f8543 100644
--- a/src/ride/ride.h
+++ b/src/ride/ride.h
@@ -349,9 +349,9 @@ typedef struct {
uint16 total_air_time; // 0x1F4
uint8 pad_1F6;
uint8 num_circuits; // 0x1F7
- sint16 var_1F8;
- sint16 var_1FA;
- uint8 var_1FC;
+ sint16 cable_lift_x; // 0x1F8
+ sint16 cable_lift_y; // 0x1FA
+ uint8 cable_lift_z; // 0x1FC
uint8 pad_1FD;
uint16 cable_lift; // 0x1FE
uint16 queue_length[4]; // 0x200
diff --git a/src/ride/track.c b/src/ride/track.c
index 4430c7aa93..258b20e1f4 100644
--- a/src/ride/track.c
+++ b/src/ride/track.c
@@ -4223,9 +4223,9 @@ static money32 track_place(int rideIndex, int type, int originX, int originY, in
if (trackBlock->index != 0)
break;
ride->lifecycle_flags |= RIDE_LIFECYCLE_16;
- ride->var_1F8 = x;
- ride->var_1FA = y;
- ride->var_1FC = baseZ;
+ ride->cable_lift_x = x;
+ ride->cable_lift_y = y;
+ ride->cable_lift_z = baseZ;
break;
case 0xD8:
ride->num_block_brakes++;
diff --git a/src/ride/vehicle.c b/src/ride/vehicle.c
index f3647fe600..6fcb060c28 100644
--- a/src/ride/vehicle.c
+++ b/src/ride/vehicle.c
@@ -23,11 +23,12 @@
#include "../audio/mixer.h"
#include "../config.h"
#include "../interface/viewport.h"
+#include "../openrct2.h"
#include "../world/sprite.h"
#include "ride.h"
#include "ride_data.h"
+#include "track.h"
#include "vehicle.h"
-#include "../openrct2.h"
static void vehicle_update(rct_vehicle *vehicle);
@@ -639,4 +640,74 @@ rct_vehicle *vehicle_get_head(rct_vehicle *vehicle)
int vehicle_is_used_in_pairs(rct_vehicle *vehicle)
{
return vehicle->num_seats & VEHICLE_SEAT_PAIR_FLAG;
-}
\ No newline at end of file
+}
+
+/**
+ *
+ * rct2: 0x006DEF56
+ */
+void sub_6DEF56(rct_vehicle *cableLift)
+{
+ RCT2_CALLPROC_X(0x006DEF56, 0, 0, 0, 0, (int)cableLift, 0, 0);
+}
+
+rct_vehicle *cable_lift_segment_create(int rideIndex, int x, int y, int z, int direction, uint16 var_44, uint32 var_24, bool head)
+{
+ rct_ride *ride = GET_RIDE(rideIndex);
+ rct_vehicle *current = &(create_sprite(1)->vehicle);
+ current->sprite_identifier = SPRITE_IDENTIFIER_VEHICLE;
+ current->ride = rideIndex;
+ current->ride_subtype = 0xFF;
+ if (head) {
+ move_sprite_to_list((rct_sprite*)current, SPRITE_LINKEDLIST_OFFSET_VEHICLE);
+ ride->cable_lift = current->sprite_index;
+ }
+ current->var_01 = head ? 0 : 1;
+ current->var_44 = var_44;
+ current->var_24 = var_24;
+ current->sprite_width = 10;
+ current->sprite_height_negative = 10;
+ current->sprite_height_positive = 10;
+ current->var_46 = 100;
+ current->num_seats = 0;
+ current->speed = 20;
+ current->var_C3 = 80;
+ current->velocity = 0;
+ current->var_2C = 0;
+ current->var_4A = 0;
+ current->var_4C = 0;
+ current->var_4E = 0;
+ current->var_B5 = 0;
+ current->var_BA = 0;
+ current->var_B6 = 0;
+ current->var_B8 = 0;
+ current->sound1_id = 0xFF;
+ current->sound2_id = 0xFF;
+ current->var_C4 = 0;
+ current->var_C5 = 0;
+ current->var_C8 = 0;
+ current->var_CC = 0xFF;
+ current->var_1F = 0;
+ current->var_20 = 0;
+ for (int j = 0; j < 32; j++) {
+ current->peep[j] = SPRITE_INDEX_NULL;
+ }
+ current->var_CD = 0;
+ current->sprite_direction = direction << 3;
+ current->var_38 = x;
+ current->var_3A = y;
+
+ z = z * 8;
+ current->var_3C = z;
+ z += RCT2_GLOBAL(0x0097D21A + (ride->type * 8), uint8);
+
+ sprite_move(16, 16, z, (rct_sprite*)current);
+ current->var_36 = (TRACK_ELEM_CABLE_LIFT_HILL << 2) | (current->sprite_direction >> 3);
+ current->var_34 = 164;
+ current->var_48 = 2;
+ current->status = VEHICLE_STATUS_MOVING_TO_END_OF_STATION;
+ current->var_51 = 0;
+ current->num_peeps = 0;
+ current->next_free_seat = 0;
+ return current;
+}
diff --git a/src/ride/vehicle.h b/src/ride/vehicle.h
index b2c95e4f7d..dc7327cb98 100644
--- a/src/ride/vehicle.h
+++ b/src/ride/vehicle.h
@@ -53,9 +53,11 @@ typedef struct {
sint16 sprite_bottom; // 0x1C
uint8 sprite_direction; // 0x1E
uint8 var_1F;
- uint8 pad_20[0x08];
+ uint8 var_20;
+ uint8 pad_21[3];
+ uint32 var_24;
sint32 velocity; // 0x28
- uint8 pad_2C[0x04];
+ uint32 var_2C;
uint8 ride; // 0x30
uint8 vehicle_type; // 0x31
rct_vehicle_colour colours; // 0x32
@@ -69,31 +71,37 @@ typedef struct {
uint16 var_3C;
uint16 next_vehicle_on_train; // 0x3E
uint16 prev_vehicle_on_train; // 0x40
- uint16 pad_42;
+ uint16 next_or_first_vehicle_on_train; // 0x42
uint16 var_44;
uint16 var_46;
uint16 var_48;
- uint8 pad_4A;
+ uint8 var_4A;
uint8 current_station; // 0x4B
- uint8 pad_4C[0x4];
+ uint16 var_4C;
+ uint16 var_4E;
uint8 status; // 0x50
uint8 var_51;
uint16 peep[32]; // 0x52
uint8 peep_tshirt_colours[32]; // 0x92
uint8 num_seats; // 0xB2
uint8 num_peeps; // 0xB3
- uint8 next_free_seat; // 0xB4
- uint8 pad_B5[0x06];
+ uint8 next_free_seat; // 0xB4
+ uint8 var_B5;
+ uint16 var_B6;
+ uint16 var_B8;
+ uint8 var_BA;
uint8 sound1_id; // 0xBB
uint8 sound1_volume; // 0xBC
uint8 sound2_id; // 0xBD
uint8 sound2_volume; // 0xBE
sint8 var_BF;
- uint8 pad_C0[0x02];
+ uint8 pad_C0[2];
uint8 speed; // 0xC2
- uint8 pad_C3[2];
+ uint8 var_C3;
+ uint8 var_C4;
uint8 var_C5;
- uint8 pad_C6[6];
+ uint8 pad_C6[2];
+ uint32 var_C8;
uint8 var_CC;
uint8 var_CD;
union {
@@ -151,6 +159,8 @@ void vehicle_get_g_forces(rct_vehicle *vehicle, int *verticalG, int *lateralG);
void vehicle_set_map_toolbar(rct_vehicle *vehicle);
int vehicle_is_used_in_pairs(rct_vehicle *vehicle);
rct_vehicle *vehicle_get_head(rct_vehicle *vehicle);
+void sub_6DEF56(rct_vehicle *cableLift);
+rct_vehicle *cable_lift_segment_create(int rideIndex, int x, int y, int z, int direction, uint16 var_44, uint32 var_24, bool head);
/** Helper macro until rides are stored in this module. */
#define GET_VEHICLE(sprite_index) &(g_sprite_list[sprite_index].vehicle)