Moin,
im folgendem seht ihr ein Tutorial zum Einfügen von Basen in einen Altis life Server der Version 5.0.0 (DIESES TUT IST NICHTS FÜR ANGÄNGER). (BILDER IM ANHANG :O)
Dieses Video haben wir damals als Promo für diese Basen gemacht(Link zum Changelog im Forum ) (Ich hab leider keine Ahnung wie ich das Video kleiner krieg )
Dieses System wurde auf einem Vanilla Altis Life Server getestet - ICH HABE KEINE AHNUNG WIE SICH INFISTAR O.Ä. DARAUF AUSWIRKT
Das System stammt ursprünglich vom Löwenherz Altis Life Server ist jedoch von mir (war/bin, eher war, da DEV :O).
Eine Funktion in diesen Dateien kommt von Lucian, hier gehts zum TUT - volle Credits an ihn.
Alle Erbauer von Basen die nicht ich sind haben der Veröffentlichung zugestimmt - Danke Bloodwyn und EL Presidente.
Diese standard Basen funktionieren NUR auf Altis.
Solltet ihr eigene Basen bauen und in das System integrieren wollen solltet ihr wissen, dass dies sehr viel Arbeit ist und man auch Ahnung haben sollte wie Dinge in Arma funktionieren. Das Einbauen der beigefügten Basen ist jedoch sehr einfach.
Gundinformationen zu diesen Basen:
- Es sind insgesamt 7 Basen die hier jetzt drin sind
- Basen haben verschiedene "Ratings"(große Basen=Rating 3/mittlere Basen=Rating 2/kleine Basen=Rating 1)
- Das Rating hat Auswirkungen auf die Mietpreise und die Mindestanzahl an Gangmitgliedern die man haben muss um eine Basis überhaupt kaufen zu können
- Für eine Basis muss man Miete zahlen, im Moment wird die Miete alle 28 Tage fällig (RL tage) - ist aber umstellbar in der Config_bases.hpp
- Basenbesitzer sehen wann und wie viel Miete sie zahlen müssen am Basenschild (Für die Miete braucht man Geld aufm Gangkonto und muss Items am Basenschild einlagern)
- Basen brauchen schon während des Ausbauens Miete
- Sollte eine Gang mal die Miete nicht bezahlen bekommt diese Basis einen Strike
- Strikes können nicht von Spielern entfernt werden, nur Leute mit DB zugriff können dies tun
- Nach 3 Strikes(kann man auch umstellen) wird die Basis zurückgesetzt und kann ab dann von einer anderen Gang wieder gekauft werden
- Abhängig vom Rating der Basen haben die Basen unteschiedliche Austattungen
- Gangmitglieder können an der Base spawnen
- Die Gang kann sich Objekte zur Basis dazu kaufen und nach belieben in der Basis platzieren
- Um ein Inventar an der Base haben zu können muss sich die Gang eine oder mehrere Kisten mit Inventar aus dem BaseShop kaufen und platzieren - Das i und T Inventar dieser Kisten ist permanent und nur Gangmitglieder können an dies ran
- Im "admin_notifications" table in der DB kann man nachvollziehen was so mit den Basen passiert ist
- Im "bases" table in der Spalte "name" könnt ihr der Basis einen Namen geben. (Wir hatten Sie damals nach Orten in "HERR DER RINGE" benannt ) - Die Spalte "author" wird aber bitte so belassen
- Sollte eine Gang eine Basis aufgeben wird diese erst nach dem nächsten Restart von der Karte gelöscht und ist erst ab dann wieder kaufbar
Das eigentliche TUT:
1. Macht Backups von eurer mission.pbo und eurem @life_server
2. OHNE SCHEIß MACHT BACKUPS WIR WERDEN SEHR VIEL ÄNDERN!
3. Ladet euch die .zip hier vom Anhang runter
4. Öffnet die ZIP
5. Wir werden jetzt mehrere Dateien austauschen, solltet ihr diese Dateien bereits bearbeitet haben guckt euch einfach die Änderungen an und übernehmt diese (!!!!!WENN IHR NICHT WISST WAS IHR TUT LASST ES SEIN!!!!!):
Die "fn_updateHouseTrunk.sqf" und "fn_updateHouseContainers.sqf" in "\life_server\Functions\Housing\" aufm Server ersetzen durch die in der ZIP (die Dateien in der ZIP zum Austauschen sind im "zu ersetzende Dateien" Ordner in der ZIP ).
Die "fn_vehicleGarage.sqf" in "Altis_Life.Altis\dialog\functions\" mit der sich in der ZIP befindlichen austauschen.
Die "fn_inventoryOpened.sqf" und "fn_inventoryClosed.sqf" in "Altis_Life.Altis\core\functions\" mit der sich in der ZIP befindlichen austauschen.
6.In die init.sqf von life_server folgendes einfügen:
diag_log "Initializing Base System...";
[] call life_fnc_initBases;
diag_log "Base System initialized";
Das muss über folgendes:
/* Tell clients that the server is ready and is accepting queries */
life_server_isReady = true;
publicVariable "life_server_isReady";
7. In "Altis_Life.Altis\core\functions\fn_keyhandler.sqf" öffnen und folgendes einfügen:
Spoiler anzeigen
//////////////////// BASE BUILD KEYS ////////////////////
case 203: // LEFT
{
if!(isnull LIFE_BASE_OBJECT) then {
LIFE_X = LIFE_X - LIFE_BASE_VALUE;
LIFE_BASE_OBJECT attachto[player,[LIFE_X,LIFE_Y,LIFE_Z]];
_handled = true;
};
};
case 205: // RIGHT
{
if!(isnull LIFE_BASE_OBJECT) then {
LIFE_X = LIFE_X + LIFE_BASE_VALUE;
LIFE_BASE_OBJECT attachto[player,[LIFE_X,LIFE_Y,LIFE_Z]];
_handled = true;
};
};
case 200: // UP
{
if!(isnull LIFE_BASE_OBJECT) then {
LIFE_Y = LIFE_Y - LIFE_BASE_VALUE;
LIFE_BASE_OBJECT attachto[player,[LIFE_X,LIFE_Y,LIFE_Z]];
_handled = true;
};
};
case 208: // DOWN
{
if!(isnull LIFE_BASE_OBJECT) then {
LIFE_Y = LIFE_Y + LIFE_BASE_VALUE;
LIFE_BASE_OBJECT attachto[player,[LIFE_X,LIFE_Y,LIFE_Z]];
_handled = true;
};
};
case 201: // BILD HOCH
{
if!(isnull LIFE_BASE_OBJECT) then {
LIFE_Z = LIFE_Z + LIFE_BASE_VALUE;
LIFE_BASE_OBJECT attachto[player,[LIFE_X,LIFE_Y,LIFE_Z]];
_handled = true;
};
};
case 209: // BILD RUNTER
{
if!(isnull LIFE_BASE_OBJECT) then {
LIFE_Z = LIFE_Z - LIFE_BASE_VALUE;
LIFE_BASE_OBJECT attachto[player,[LIFE_X,LIFE_Y,LIFE_Z]];
_handled = true;
};
};
case 28: // ENTER
{
if!(isnull LIFE_BASE_OBJECT) then {
0 spawn life_fnc_place_base_object;
};
};
//////////////////// BASE BUILD KEYS END////////////////////
Alles anzeigen
das muss unter:
// -- Disable commander/tactical view
if (LIFE_SETTINGS(getNumber,"disableCommanderView") isEqualTo 1) then {
private _CommandMode = actionKeys "tacticalView";
if (_code in _CommandMode) then {
hint localize "STR_NOTF_CommanderView";
_handled = true;
};
};
8. IN "Altis_Life.Altis\dialog\function\fn_spawnPointCfg.sqf" folgendes einfügen:
_ret = 0 call life_fnc_get_base_player;
if!(isnull (_ret select 0)) then {
_marker = createMarkerLocal ["LIFE_myBase",getpos(_ret select 0)];
_return pushback ["LIFE_myBase",(format["Base: %2(lvl %1) ",_ret select 1,_ret select 2]),"\a3\ui_f\data\map\MapControl\custommark_ca.paa"];
};
das muss direkt unter(also zwischen die beiden if-statements sollte eure Datei standardmäßig sein):
9. Den SQL Code aus "base_SQL_CODE.sql" (die Datei findet ihr in der .ZIP) in der DB ausführen(Das müsst ihr natürlich mit einem Acc machen der entsprechende Rechte hat)
10. Folgendes in die "Altis_Life.Altis\core\configuration.sqf" einfügen(ist eig egal wohin(solange ihrs nicht in die foreach-Schleifen packt)):
// BASE VARS
LIFE_BASE_OBJECT = objNull;
LIFE_Y = 10;
LIFE_X = 0;
LIFE_Z = 0;
LIFE_BASE_VALUE = 0.1;
LIFE_VehShop_Showcase = false;
LIFE_shop_show_vehicle = ObjNull;
LIFE_VehShop_Dir = 0;
LIFE_shop_Rotate_speed = 0.2;
LIFE_shop_cam = ObjNull;
LIFE_shop_light = ObjNull;
LIFE_distance_cam = 30;
// BASE VARS END
Alles anzeigen
11.Config_bases.hpp aus dem Ordner "\Config\" in der ZIP in "Altis_Life.Altis\config\" einfügen und ganz unten in der "Config_Master.hpp" (im selbem Verzeichnis) folgendes einfügen:
12. In der "life_server\Functions\Systems\fn_spawnvehicle.sqf" ersetzt ihr:
durch:
13.Server Dateien einfügen:
In "life_server/Functions" neuen Ordner namens "Bases" erstellen, da alle Dateien von der ZIP aus dem Ordner Base_server reinkopieren.
14. In der config.cpp (immer noch in life_server) unter der Klasse von "wanted_sys" folgendes eintragen (Mit unter der Klasse ist nicht in der Klasse gemeint sondern darunter):
class Bases {
file = "\life_server\Functions\Bases";
class base_activity_check {};
class base_material_request {};
class base_rental_sync{};
class basedelete_fromgang{};
class baseLevelUp{};
class dayCheck{};
class delete_base_object {};
class get_randomized_base_rent {};
class initBases {};
class insert_base_object {};
class sync_base_material {};
class update_base_object {};
class Insert_admin_notifiaction {};
};
Alles anzeigen
15. Jetzt fügt ihr alles aus dem Ordner "bases_client" (also auch die Ordner) in der ZIP in einen Ordner den ihr in "\Altis_Life.Altis\core" erstellt und "bases" nennt.
16.Die Functions.hpp in der Altis_Life.Altis öffnen und folgendes unter der Klasse von Admin einfügen:
class bases_client {
file = "core\bases";
class base_config {};
class base_jail {};
class create_base {};
class delete_bought_object {};
class gang_get_rank {};
class get_all_bought_objects {};
class get_base_conf {};
class get_base_player {};
class get_base_rent {};
class getMaxBaseLevel {};
class init_bases_client {};
class monitor_base_object_placing {};
class object_add_addaction {};
class pay_with_gang_bank {};
class place_base_object {};
class preview_base {};
class sell_base {};
class upgradeBaseInProgress {};
class exp_hint {};
class circleVehicleShow {};
class mresArray {};
class mresString {};
class mresToArray {};
class numberSafe {};
class stand_up_seat {};
class take_seat {};
};
class bases_client_dialog {
file = "core\bases\dialog_functions";
class admin_force_material {};
class base_build_dialog_buy {};
class base_build_dialog_demo {};
class base_build_dialog_open {};
class ClaimBTN_base_apply_dialog {};
class EVH_base_apply_dialog {};
class materialRET_base_storage_dialog {};
class materialRET_base_storage_dialog_rent {};
class open_base_apply_dialog {};
class open_base_storage_dialog {};
class open_base_storage_dialog_rent {};
class prepare_base_level_up {};
class store_action_base_storage_dialog {};
class sync_building_mats_toServer {};
class update_base_storage_dialog {};
};
Alles anzeigen
17. Ihr ersetzt in der "Altis_Life.Altis\core\functions\fn_keyhandler.sqf" folgendes:
//T Key (Trunk)
case 20: {
if (!_alt && {!_ctrlKey} && {!dialog} && {!life_action_inUse} && {!(player getVariable ["playerSurrender",false])} && {!(player getVariable ["restrained",false])} && {!life_isknocked} && {!life_istazed}) then {
if (!(isNull objectParent player) && alive vehicle player) then {
if ((vehicle player) in life_vehicles) then {
[vehicle player] spawn life_fnc_openInventory;
};
} else {
private "_list";
_list = ((ASLtoATL (getPosASL player)) nearEntities [["Box_IND_Grenades_F","B_supplyCrate_F"], 2.5]) select 0;
if (!(isNil "_list")) then {
_house = nearestObject [(ASLtoATL (getPosASL _list)), "House"];
if (_house getVariable ["locked", false]) then {
hint localize "STR_House_ContainerDeny";
} else {
[_list] spawn life_fnc_openInventory;
};
} else {
_list = ["landVehicle","Air","Ship"];
if (KINDOF_ARRAY(cursorObject,_list) && {player distance cursorObject < 7} && {isNull objectParent player} && {alive cursorObject} && {!life_action_inUse}) then {
if (cursorObject in life_vehicles || {locked cursorObject isEqualTo 0}) then {
[cursorObject] spawn life_fnc_openInventory;
};
};
};
};
};
};
Alles anzeigen
durch:
//T Key (Trunk)
case 20: {
if (!_alt && {!_ctrlKey} && {!dialog} && {!life_action_inUse} && {!(player getVariable ["playerSurrender",false])} && {!(player getVariable ["restrained",false])} && {!life_isknocked} && {!life_istazed}) then {
if (!(isNull objectParent player) && alive vehicle player) then {
if ((vehicle player) in life_vehicles) then {
[vehicle player] spawn life_fnc_openInventory;
};
} else {
private "_list";
_list = ((ASLtoATL (getPosASL player)) nearEntities [["Box_IND_Grenades_F","B_supplyCrate_F"], 2.5]) select 0;
if (!(isNil "_list")) then {
_house = nearestObject [(ASLtoATL (getPosASL _list)), "House"];
if (_house getVariable ["locked", false]) then {
hint localize "STR_House_ContainerDeny";
} else {
[_list] spawn life_fnc_openInventory;
};
} else {
_list = ["landVehicle","Air","Ship"];
if (KINDOF_ARRAY(cursorObject,_list) && {player distance cursorObject < 7} && {isNull objectParent player} && {alive cursorObject} && {!life_action_inUse}) then {
if (cursorObject in life_vehicles || {locked cursorObject isEqualTo 0}) then {
[cursorObject] spawn life_fnc_openInventory;
};
};
};
if((typeof cursorObject) in ["Box_IND_Grenades_F","B_supplyCrate_F"] && cursorObject getVariable["LIFE_BASE_OBJECT_ID",-1] >= 0) then {
[cursorObject] spawn life_fnc_openInventory;
};
};
};
};
Alles anzeigen
18. Ihr kopiert den Ordner "bases" aus der ZIP in "Altis_Life.Altis\dialog\".
19. Wir gehen in die "MasterHandler.hpp" in "Altis_Life.Altis\dialog\" und fügen ganz unten folgendes ein:
// Base Dialogs
#include "bases\base_apply.hpp"
#include "bases\base_build_dialog.hpp"
#include "bases\base_info_dialog.hpp"
#include "bases\base_storage_dialog.hpp"
// Base Dialogs end
20. In "Altis_Life.Altis\core\init.sqf" über:
addMissionEventHandler ["EachFrame", life_fnc_playerTags];
addMissionEventHandler ["EachFrame", life_fnc_revealObjects];
folgendes einfügen:
21. In der CfgRemoteexec folgende Funktionen einfügen:
// BASES START
F(life_fnc_upgradeBaseInProgress,ANYONE)
F(BIS_fnc_dynamicText,ANYONE)
F(life_fnc_create_base,ANYONE)
F(life_fnc_object_add_addaction,ANYONE)
F(life_fnc_materialRET_base_storage_dialog,CLIENT)
F(life_fnc_materialRET_base_storage_dialog_rent,CLIENT)
F(life_fnc_baseLevelUp,SERVER)
F(life_fnc_base_material_request,SERVER)
F(life_fnc_sync_base_material,SERVER)
F(life_fnc_base_rental_sync,SERVER)
F(life_fnc_delete_base_object,SERVER)
F(life_fnc_update_base_object,SERVER)
F(life_fnc_basedelete_fromgang,SERVER)
F(life_fnc_insert_base_object,SERVER)
// BASES END
Alles anzeigen
22. unsafeCVL in der "description.ext" muss auf 1 stehen.
FIN. Damit könnt ihr jetzt das System und die Standard-Basen nutzen
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Wie fügt man neue Basen ein? (Das ist vll jetzt keine krass ausführliche Erklärung aber das würde mir zu lange dauern, sry )
Ihr baut eine Basis im Editor(halt auf der Karte auf der euer Server ist und an der Position an der die Basis sein soll).
Ihr setzt diese Variablen auf die Objekte die diese brauchen:
this setvariable["Server",true]; // Das objekt muss vom Server erstellt werden z.B. Türme wegen ihrer Türen und Fenster
this setvariable["sim",true]; // Die Simulation von diesem Objekt muss eingeschaltet bleiben z.B. bei Lamepn
this setvariable["disallowdamage",true]; // solltet ihr mal ein objekt haben bei dem ihr den Damage anstellen wollt auf true setzen - standard ist halt off
this setvariable["not",true]; // ein Objekt mit dieser Variable mit nicht beachtet und nicht in die Variable "arr" eingetragen
Jetzt stellt ihr euch in die Mitte der Basis und führt folgendes aus:
arr = [];
_objekte = nearestobjects[player,["ALL"],200]; // passt diesen radius so an wie ihr in braucht
_objekte = _objekte - [player];
{
if!(_x getvariable["not",false]) then {
if!(typeof _x in ["Rabbit_F","Snake_random_F"]) then {
if(_x getvariable["Server",false] && _x getvariable["sim",false]) then {
if(_x getvariable["disallowdamage",false]) then {
arr pushback [typeof _x,getposatl _x,getdir _x,[],[],true,true,"",true,[vectordir _x,vectorUp _x]];
}else {
arr pushback [typeof _x,getposatl _x,getdir _x,[],[],true,true,"",false,[vectordir _x,vectorUp _x]];
};
} else {
if(_x getvariable["Server",false]) then {
if(_x getvariable["disallowdamage",false]) then {
arr pushback [typeof _x,getposatl _x,getdir _x,[],[],false,true,"",true,[vectordir _x,vectorUp _x]];
}else {
arr pushback [typeof _x,getposatl _x,getdir _x,[],[],false,true,"",false,[vectordir _x,vectorUp _x]];
};
};
if(_x getvariable["sim",false]) then {
if(_x getvariable["disallowdamage",false]) then {
arr pushback [typeof _x,getposatl _x,getdir _x,[],[],true,false,"",true,[vectordir _x,vectorUp _x]];
}else {
arr pushback [typeof _x,getposatl _x,getdir _x,[],[],true,false,"",false,[vectordir _x,vectorUp _x]];
};
};
};
};
};
} foreach _objekte;
Alles anzeigen
Danach lest ihr die Variable arr aus und fügt ihren Inhalt in das entsprechende switch case statement in der fn_base_config.sqf ein.
Die ID aus dem "bases-table" weist diesen Eintrag in der DB der Config in der base_config.sqf zu.
D.h. solltet ihr eine neue Basis machen wollen und die alten behalten wollen erstellt ihr eine neue Zeile mit der ID 8 und fügt inder fn_base_config.sqf noch ein case-statement mit dem argument 8 ein.
Dort fügt ihr dann die configs für diese Base ein.
In der fn_Base_config.sqf in Zeile 252 und höher findet ihr Kommentare die euch hoffentlich weiterhelfen.
Ansonsten könnt ihr auch nocht Einstellungen in der Bases_config.hpp ändern.
MfG Barney