|
149 | 149 | #include "packets/s2c/0x063_miscdata_job_points.h" |
150 | 150 | #include "packets/s2c/0x063_miscdata_merits.h" |
151 | 151 | #include "packets/s2c/0x063_miscdata_monstrosity.h" |
| 152 | +#include "packets/s2c/0x069_chocobo_racing.h" |
152 | 153 | #include "packets/s2c/0x075_battlefield.h" |
153 | 154 | #include "packets/s2c/0x077_entity_vis.h" |
154 | 155 | #include "packets/s2c/0x082_guild_buy.h" |
@@ -1127,6 +1128,112 @@ void CLuaBaseEntity::sendLinkshellConcierge(const sol::table& data) const |
1127 | 1128 | } |
1128 | 1129 | } |
1129 | 1130 |
|
| 1131 | +/************************************************************************ |
| 1132 | + * Function: sendChocoboRace() |
| 1133 | + * Purpose : Send the entire chocobo race content to the player. |
| 1134 | + * Note : Complex API, see chocobo_racing.lua for usage. |
| 1135 | + ************************************************************************/ |
| 1136 | +void CLuaBaseEntity::sendChocoboRace(const sol::table& race) const |
| 1137 | +{ |
| 1138 | + auto* PChar = dynamic_cast<CCharEntity*>(m_PBaseEntity); |
| 1139 | + if (!PChar) |
| 1140 | + { |
| 1141 | + return; |
| 1142 | + } |
| 1143 | + |
| 1144 | + // Read a 1-indexed lua table of per-chocobo values (positions or places) into a fixed array. |
| 1145 | + const auto readNibbles = [](const sol::table& values) -> std::array<uint8, GP_SERV_COMMAND_CHOCOBO_RACING::kNumRacers> |
| 1146 | + { |
| 1147 | + std::array<uint8, GP_SERV_COMMAND_CHOCOBO_RACING::kNumRacers> out{}; |
| 1148 | + for (uint8 racer = 0; racer < GP_SERV_COMMAND_CHOCOBO_RACING::kNumRacers; ++racer) |
| 1149 | + { |
| 1150 | + out[racer] = values.get_or<uint8>(racer + 1, 0); |
| 1151 | + } |
| 1152 | + |
| 1153 | + return out; |
| 1154 | + }; |
| 1155 | + |
| 1156 | + // Mode 1: Race parameters |
| 1157 | + PChar->pushPacket<GP_SERV_COMMAND_CHOCOBO_RACING::RACINGPARAMS>(race.get_or<uint32>("weather", 1), race.get_or<uint32>("counter", 0)); // 1 = xi.weather.SUNSHINE (clear) |
| 1158 | + |
| 1159 | + // Mode 2: Racing Chocobos |
| 1160 | + if (const auto chocobos = race.get<sol::optional<sol::table>>("chocobos")) |
| 1161 | + { |
| 1162 | + const auto count = std::min<size_t>(chocobos->size(), GP_SERV_COMMAND_CHOCOBO_RACING::kNumRacers); |
| 1163 | + std::vector<GP_SERV_COMMAND_CHOCOBO_RACING::ChocoboParam> entries(count); |
| 1164 | + |
| 1165 | + for (size_t idx = 1; idx <= count; ++idx) |
| 1166 | + { |
| 1167 | + auto& entry = entries[idx - 1]; |
| 1168 | + const auto data = chocobos->get<sol::table>(idx); |
| 1169 | + |
| 1170 | + entry.Item = data.get_or<uint8>("item", 0); // equipped item (sectionEvent) |
| 1171 | + entry.Orders = data.get_or<uint8>("orders", 0); // jockey orders |
| 1172 | + entry.Size = data.get_or<uint8>("size", 0); // jockey (jockeySize) |
| 1173 | + entry.Color = data.get_or<uint8>("color", 0); // plumage colour |
| 1174 | + entry.Gender = data.get_or<uint8>("gender", 0); |
| 1175 | + entry.Weather = data.get_or<uint8>("weather", 0); // preferred weather (xi.chocoboRaising.weather) |
| 1176 | + entry.Temperament = data.get_or<uint8>("temperament", 0); // display/raising trait; no race effect |
| 1177 | + entry.Ability1 = data.get_or<uint8>("ability1", 0); // xi.chocoboRaising.ability (Gallop/Canter/...) |
| 1178 | + entry.Ability2 = data.get_or<uint8>("ability2", 0); |
| 1179 | + |
| 1180 | + // Racing stats (chococard ranks 0-7 = F..SS): STR/END/DSC/RCP. |
| 1181 | + if (const auto stats = data.get<sol::optional<sol::table>>("stats")) |
| 1182 | + { |
| 1183 | + entry.STR.Rank = stats->get_or<uint8>("str", 0); |
| 1184 | + entry.END.Rank = stats->get_or<uint8>("end", 0); |
| 1185 | + entry.DSC.Rank = stats->get_or<uint8>("dsc", 0); |
| 1186 | + entry.RCP.Rank = stats->get_or<uint8>("rcp", 0); |
| 1187 | + } |
| 1188 | + } |
| 1189 | + |
| 1190 | + PChar->pushPacket<GP_SERV_COMMAND_CHOCOBO_RACING::CHOCOBOPARAMS>(entries); |
| 1191 | + } |
| 1192 | + |
| 1193 | + // Mode 3: Racing sections, 16 sections per packet. |
| 1194 | + if (const auto raceSections = race.get<sol::optional<sol::table>>("sections")) |
| 1195 | + { |
| 1196 | + const size_t sectionCount = std::min<size_t>(raceSections->size(), GP_SERV_COMMAND_CHOCOBO_RACING::kMaxSections); |
| 1197 | + std::vector<GP_SERV_COMMAND_CHOCOBO_RACING::SectionParam> sections(sectionCount); |
| 1198 | + |
| 1199 | + for (size_t idx = 1; idx <= sectionCount; ++idx) |
| 1200 | + { |
| 1201 | + const auto sec = raceSections->get<sol::table>(idx); |
| 1202 | + auto& section = sections[idx - 1]; |
| 1203 | + |
| 1204 | + GP_SERV_COMMAND_CHOCOBO_RACING::packNibbles(section.From, readNibbles(sec.get<sol::table>("from"))); |
| 1205 | + GP_SERV_COMMAND_CHOCOBO_RACING::packNibbles(section.To, readNibbles(sec.get<sol::table>("to"))); |
| 1206 | + |
| 1207 | + if (const auto event = sec.get<sol::optional<sol::table>>("trigger")) |
| 1208 | + { |
| 1209 | + section.Trigger.User = event->get_or<uint8>("user", 0); |
| 1210 | + section.Trigger.Targets = event->get_or<uint8>("targets", 0); |
| 1211 | + section.Trigger.Param = event->get_or<uint8>("param", 0); |
| 1212 | + section.Trigger.Type = static_cast<GP_SERV_COMMAND_CHOCOBO_RACING::SectionEventType>(event->get_or<uint8>("type", 0)); |
| 1213 | + } |
| 1214 | + } |
| 1215 | + |
| 1216 | + // Each packet carries up to kSectionsPerPacket sections; |
| 1217 | + // ParamIndex is the starting section index. |
| 1218 | + for (size_t offset = 0; offset < sections.size(); offset += GP_SERV_COMMAND_CHOCOBO_RACING::kSectionsPerPacket) |
| 1219 | + { |
| 1220 | + const auto end = std::min(offset + GP_SERV_COMMAND_CHOCOBO_RACING::kSectionsPerPacket, sections.size()); |
| 1221 | + |
| 1222 | + std::vector<GP_SERV_COMMAND_CHOCOBO_RACING::SectionParam> chunk(sections.begin() + offset, sections.begin() + end); |
| 1223 | + PChar->pushPacket<GP_SERV_COMMAND_CHOCOBO_RACING::SECTIONPARAMS>(static_cast<uint8>(offset), chunk); |
| 1224 | + } |
| 1225 | + } |
| 1226 | + |
| 1227 | + // Mode 4: Final race results. |
| 1228 | + if (const auto places = race.get<sol::optional<sol::table>>("places")) |
| 1229 | + { |
| 1230 | + PChar->pushPacket<GP_SERV_COMMAND_CHOCOBO_RACING::RESULTPARAMS>(readNibbles(*places)); |
| 1231 | + } |
| 1232 | + |
| 1233 | + // Mode 5: Notify client exchange is done. |
| 1234 | + PChar->pushPacket<GP_SERV_COMMAND_CHOCOBO_RACING::END>(); |
| 1235 | +} |
| 1236 | + |
1130 | 1237 | /************************************************************************ |
1131 | 1238 | * Helper function for the lua bindings that start events. |
1132 | 1239 | ************************************************************************/ |
@@ -20153,6 +20260,7 @@ void CLuaBaseEntity::Register() |
20153 | 20260 | SOL_REGISTER("entityAnimationPacket", CLuaBaseEntity::entityAnimationPacket); |
20154 | 20261 | SOL_REGISTER("sendDebugPacket", CLuaBaseEntity::sendDebugPacket); |
20155 | 20262 | SOL_REGISTER("sendLinkshellConcierge", CLuaBaseEntity::sendLinkshellConcierge); |
| 20263 | + SOL_REGISTER("sendChocoboRace", CLuaBaseEntity::sendChocoboRace); |
20156 | 20264 |
|
20157 | 20265 | SOL_REGISTER("startEvent", CLuaBaseEntity::startEvent); |
20158 | 20266 | SOL_REGISTER("startCutscene", CLuaBaseEntity::startCutscene); |
|
0 commit comments