[Aide] Script Changement de textures + option delete script

Répondre
Partager Rechercher
Bonjour,

J'aurais besoin d'un coup de main pour créer un script de changement de textures par l'intermédiaire d'une boite de dialogue (menu bleu)
Le but est quand je clic sur mon objet un menu s'ouvre et me permette de choisir de modifier la texture ou bien de delete le script quand j'ai fini de choisir ma texture.
J'aimerais que les textures soient dans une notecard sous formes d'uuid.
J'ai trouvé un script de changement de texture par notecard et uuid, peut-être un peu ancien mais qui fonctionne, j'ai tenté depuis hier de bricoler et d'ajouter cette option de delete de script
mais pas assez de connaissance.
Si quelqu'un pouvait m'aider ce serait génial.

Merci beaucoup

// Script to present a dialog populated with a list of textures
// either from the prims inventory or specified by UUID in a notecard.
//
// Notecard lines have the form:
// Texture Name=UUID
//
// Note that only the first 24 characters of the texture names
// are actually used - as only 24 chars can be placed in a dialog
// button. This means that if two textures have the first 24 chars
// the same, the second will be ignored ...
//
// Note however that usually, buttons don't display more than, say,
// around 10 or so characters anyway!!
//
// There are two methods of setting textures - one (gSetTexture = TRUE)
// allows you to use UUIDs, etc, but the other (gSetTexture = FALSE)
// will allow you to specify the rotation and offset values.
//
// There is also an option to just use the values from the texture already
// on the face (but this won't work for ALL_SIDES).
//
// Both allow you to set the face.
//
// Kimm Paulino
// Feb 2012

// Controls how the script operates:
integer gReshow = FALSE;
integer gSetTexture = FALSE; // Use SetTexture method (needed for textures not in the prim inventory)
integer gNotecards = FALSE; // Get textures to use from a notecard not inventory
integer gPreserveTextures = FALSE; // Read offset/rotation values from existing texture

// configures how textures appear
integer gFace = ALL_SIDES;
vector gRepeats = <1.0, 1.0, 1.0>;
vector gOffsets = <1.0, 1.0, 1.0>;
float gRotationInDegrees = 0.0;

// Do not change anything below this line (unless you know what you are doing)
integer gDebug = FALSE;
integer gMenuPage;
integer gNumTextures;
list gTextures;
list gTextureUUIDs;

string gNotecardName;
integer gNotecardLine = 0;
key gQueryID;

integer gListenChannel;
integer gListenHandle;
float gListenTimer;
float LISTEN_TIMEOUT=300.0;

string MENU_NEXT="Next>";
string MENU_TOP="Top";
string MENU_BACK="<Back";
string MENU_SPACE=" ";

doDebug (string msg)
{
if (gDebug)
{
llOwnerSay (msg);
}
}

integer getRandomChannel ()
{
// Based on http://tali.appspot.com/html/scripting/snippets.html
// Always leaves 17th bit set (so never a number less than 65535)
// Always leaves sign bit unset (so is always positive)
integer pos_int = (((integer)llFrand(16384)) << 17) | 65536 | ((integer)llFrand(65535));
return -pos_int;
}

integer read_textures_from_inventory ()
{
gNumTextures = llGetInventoryNumber (INVENTORY_TEXTURE);
gTextures = [];

integer i;
for (i=0; i<gNumTextures; i++)
{
string texture = llGetInventoryName (INVENTORY_TEXTURE, i);
// Only store the first 24 characters of the name as this is all we can
// show in a dialog anyway
gTextures += [llGetSubString (texture, 0, 23)];
doDebug ("read_textures: adding texture: " + texture);
}

return gNumTextures;
}

integer read_textures_from_notecards ()
{
// Read texture information from the first notecard in inventory
gNotecardName = llGetInventoryName(INVENTORY_NOTECARD, 0);
if (gNotecardName == "")
{
return FALSE;
}
else
{
gQueryID = llGetNotecardLine(gNotecardName, gNotecardLine);
return TRUE;
}
}

set_texture (string texture)
{
if (gSetTexture)
{
llSetTexture (texture, gFace);
}
else if (gPreserveTextures && gFace != ALL_SIDES)
{
// returns: [string texture, vector scale, vector offset, float rotation]
list scale_offset_rot = llGetPrimitiveParams ([PRIM_TEXTURE, gFace]);

llSetPrimitiveParams([PRIM_TEXTURE,
gFace,
texture,
llList2Vector (scale_offset_rot, 1),
llList2Vector (scale_offset_rot, 2),
llList2Float (scale_offset_rot, 3)]
);
}
else
{
llSetPrimitiveParams([PRIM_TEXTURE,
gFace,
texture,
gRepeats,
gOffsets,
gRotationInDegrees*DEG_TO_RAD]
);
}
}

apply_texture (string texture)
{
integer idx = llListFindList (gTextures, [texture]);
if (idx == -1)
{
// Didn't find it in the list - might not be a texture
return;
}

// Now need to find the texture that matches from the inventory
// and give it out
integer i;
for (i=0; i<gNumTextures ; i++)
{
if (gNotecards)
{
string texture_uuid = llList2Key (gTextureUUIDs, idx);
if (texture_uuid != "")
{
doDebug ("apply_texture: applying texture: " + texture_uuid);
set_texture (texture_uuid);
return;
}
}
else
{
string texture_full = llGetInventoryName(INVENTORY_TEXTURE, i);
if (llGetSubString (texture_full, 0, 23) == texture)
{
// This is the one
doDebug ("apply_texture: applying texture: " + texture_full);
set_texture (texture_full);
return;
}
}
}
}

show_dialog (key id)
{
list buttons = [];

if (gNumTextures == 0)
{
do_dialog (id, "There are no textures to select at present.", []);
return;
}

// If several people are using the giver, then it is possible
// for gMenuPage to go negative or too high
if (gMenuPage < 0)
{
// Reset ...
gMenuPage = 0;
}
integer num_pages = ((gNumTextures+8)/9);
if (gMenuPage >= num_pages)
{
// gMenuPage is an index starting at 0...
// max is a 1...
gMenuPage = num_pages-1;
}

// Max buttons on a dialog is 12, so if more than that, then need to
// include special next/back button handling
integer first_texture = 0;
integer last_texture = gNumTextures-1;
if (gNumTextures > 12)
{
// Note: This yields notecards counting as follows:
// 0 to 8 = first page,
// 9 to 17 = next page, etc
first_texture = gMenuPage * 9;
last_texture = first_texture + 9 - 1;
if (last_texture >= gNumTextures)
{
// recall last_texture indexed from 0, but
// gNumTextures is indexed from 1
last_texture = gNumTextures-1;
}

if (gMenuPage > 0)
{
buttons += [MENU_BACK];
}
else
{
buttons += [MENU_SPACE];
}

if (gMenuPage == 0)
{
buttons += [MENU_SPACE];
}
else
{
buttons += [MENU_TOP];
}

// If not on the last page, and there are more pages to come ...
if (gNumTextures > 9 && gMenuPage < (num_pages-1))
{
buttons += [MENU_NEXT];
}
else
{
buttons += [MENU_SPACE];
}
}

integer i;
for (i=first_texture; (i <= last_texture) && (i < gNumTextures); i++)
{
buttons += [llList2String (gTextures, i)];
}

do_dialog (id, "\n\n(click "Ignore" when done)", buttons);
}

do_dialog (key id, string msg, list buttons)
{
llListenRemove (gListenHandle);
gListenChannel = getRandomChannel();
gListenHandle = llListen (gListenChannel, "", id, "");
llSetTimerEvent (LISTEN_TIMEOUT);
llDialog (id, msg, buttons, gListenChannel);
}

default
{
on_rez (integer start_param)
{
llResetScript();
}

state_entry()
{
if (read_textures_from_inventory())
{
// We have textures in the inventory and have read them
gNotecards = FALSE;
}
else if (read_textures_from_notecards())
{
// We have textures read in from a notecard by UUID
// (or will have pretty soon)
gNotecards = TRUE;
}
else
{
llOwnerSay ("Note: There are no textures or notecards in this prim ...");
}
gMenuPage = 0;
}

touch_start(integer total_number)
{
// Start menu system again. Note that I don't do anything special
// with several people trying to touch it at the same time - it will
// always overlap the processing of gMenuPage, but all that will
// happen is that peoples next/back might be a bit quirky for a while.
// Eventually, they will sort themselves out!
gMenuPage = 0;
show_dialog (llDetectedKey(0));
}

listen (integer channel, string name, key id, string msg)
{
if (channel == gListenChannel)
{
if (msg == MENU_BACK)
{
gMenuPage--;
show_dialog (id);
}
else if (msg == MENU_TOP)
{
gMenuPage = 0;
show_dialog (id);
}
else if (msg == MENU_NEXT)
{
gMenuPage++;
show_dialog (id);
}
else
{
// should be something in the inventory to give out
apply_texture (msg);

// reshow the dialog
if (gReshow)
{
show_dialog(id);
}
}
}
}

timer ()
{
// First see if we are timing out on a listen event
if (gListenHandle != 0)
{
// Remove the old listen
llListenRemove (gListenHandle);
gListenHandle = 0;
gListenChannel = 0;
}
}

dataserver(key query_id, string line)
{
if (query_id == gQueryID)
{
if (line != EOF)
{
if (llSubStringIndex (line, "=") != 0)
{
list vals = llParseString2List (line, ["="], []);

// Only store the first 24 characters of the name as this is all we can
// show in a dialog anyway
string texture = llList2String (vals, 0);
string uuid = llList2Key (vals, 1);
gTextures += [llGetSubString (texture, 0, 23)];
gTextureUUIDs += uuid;
doDebug ("Adding: " + texture + " ("+uuid+")");
}

// Now get the next line
gNotecardLine++;
gQueryID = llGetNotecardLine(gNotecardName, gNotecardLine);
}
else
{
gNumTextures = llGetListLength (gTextures);
doDebug ("Found " + (string)gNumTextures + " textures.");
}
}
}

changed (integer change)
{
if (change & CHANGED_INVENTORY)
{
llResetScript();
}
}
}

Dernière modification par skanajo ; 22/11/2019 à 20h25. Motif: Auto-fusion
Bon, pour bien faire, faudrait reprendre tout le script, mais a minima, on peut faire ça....




integer gReshow = FALSE;
integer gSetTexture = FALSE; // Use SetTexture method (needed for textures not in the prim inventory)
integer gNotecards = FALSE; // Get textures to use from a notecard not inventory
integer gPreserveTextures = FALSE; // Read offset/rotation values from existing texture

// configures how textures appear
integer gFace = ALL_SIDES;
vector gRepeats = <1.0, 1.0, 1.0>;
vector gOffsets = <1.0, 1.0, 1.0>;
float gRotationInDegrees = 0.0;

// Do not change anything below this line (unless you know what you are doing)
integer gDebug = FALSE;
integer gMenuPage;
integer gNumTextures;
list gTextures;
list gTextureUUIDs;

string gNotecardName;
integer gNotecardLine = 0;
key gQueryID;

integer gListenChannel;
integer gListenHandle;
float gListenTimer;
float LISTEN_TIMEOUT=300.0;

string MENU_NEXT="Next>";
string MENU_TOP="Top";
string MENU_BACK="<Back";
string MENU_SPACE=" ";
string MENU_DEL="Del. Script";

doDebug (string msg)
{
if (gDebug)
{
llOwnerSay (msg);
}
}

integer getRandomChannel ()
{
integer pos_int = (((integer)llFrand(16384)) << 17) | 65536 | ((integer)llFrand(65535));
return -pos_int;
}

integer read_textures_from_inventory ()
{
gNumTextures = llGetInventoryNumber (INVENTORY_TEXTURE);
gTextures = [];

integer i;
for (i=0; i<gNumTextures; i++)
{
string texture = llGetInventoryName (INVENTORY_TEXTURE, i);
// Only store the first 24 characters of the name as this is all we can
// show in a dialog anyway
gTextures += [llGetSubString (texture, 0, 23)];
doDebug ("read_textures: adding texture: " + texture);
}

return gNumTextures;
}

integer read_textures_from_notecards ()
{
// Read texture information from the first notecard in inventory
gNotecardName = llGetInventoryName(INVENTORY_NOTECARD, 0);
if (gNotecardName == "")
{
return FALSE;
}
else
{
gQueryID = llGetNotecardLine(gNotecardName, gNotecardLine);
return TRUE;
}
}

set_texture (string texture)
{
if (gSetTexture)
{
llSetTexture (texture, gFace);
}
else if (gPreserveTextures && gFace != ALL_SIDES)
{
// returns: [string texture, vector scale, vector offset, float rotation]
list scale_offset_rot = llGetPrimitiveParams ([PRIM_TEXTURE, gFace]);

llSetPrimitiveParams([PRIM_TEXTURE,
gFace,
texture,
llList2Vector (scale_offset_rot, 1),
llList2Vector (scale_offset_rot, 2),
llList2Float (scale_offset_rot, 3)]
);
}
else
{
llSetPrimitiveParams([PRIM_TEXTURE,
gFace,
texture,
gRepeats,
gOffsets,
gRotationInDegrees*DEG_TO_RAD]
);
}
}

apply_texture (string texture)
{
integer idx = llListFindList (gTextures, [texture]);
if (idx == -1)
{
// Didn't find it in the list - might not be a texture
return;
}

// Now need to find the texture that matches from the inventory
// and give it out
integer i;
for (i=0; i<gNumTextures ; i++)
{
if (gNotecards)
{
string texture_uuid = llList2Key (gTextureUUIDs, idx);
if (texture_uuid != "")
{
doDebug ("apply_texture: applying texture: " + texture_uuid);
set_texture (texture_uuid);
return;
}
}
else
{
string texture_full = llGetInventoryName(INVENTORY_TEXTURE, i);
if (llGetSubString (texture_full, 0, 23) == texture)
{
// This is the one
doDebug ("apply_texture: applying texture: " + texture_full);
set_texture (texture_full);
return;
}
}
}
}

show_dialog (key id)
{
list buttons = [MENU_DEL];

if (gNumTextures == 0)
{
do_dialog (id, "There are no textures to select at present.", []);
return;
}

// If several people are using the giver, then it is possible
// for gMenuPage to go negative or too high
if (gMenuPage < 0)
{
// Reset ...
gMenuPage = 0;
}
integer num_pages = ((gNumTextures+8)/9);
if (gMenuPage >= num_pages)
{
// gMenuPage is an index starting at 0...
// max is a 1...
gMenuPage = num_pages-1;
}

// Max buttons on a dialog is 12, so if more than that, then need to
// include special next/back button handling
integer first_texture = 0;
integer last_texture = gNumTextures-1;
if (gNumTextures > 12)
{
// Note: This yields notecards counting as follows:
// 0 to 8 = first page,
// 9 to 17 = next page, etc
first_texture = gMenuPage * 8;
last_texture = first_texture + 8 - 1;
if (last_texture >= gNumTextures)
{
// recall last_texture indexed from 0, but
// gNumTextures is indexed from 1
last_texture = gNumTextures-1;
}

if (gMenuPage > 0)
{
buttons += [MENU_BACK];
}
else
{
buttons += [MENU_SPACE];
}

if (gMenuPage == 0)
{
buttons += [MENU_SPACE];
//buttons += [MENU_DEL];
}
else
{
buttons += [MENU_TOP];
//buttons += [MENU_DEL];
}

// If not on the last page, and there are more pages to come ...
if (gNumTextures > 9 && gMenuPage < (num_pages-1))
{
buttons += [MENU_NEXT];
}
else
{
buttons += [MENU_SPACE];
}
}

integer i;
for (i=first_texture; (i <= last_texture) && (i < gNumTextures); i++)
{
buttons += [llList2String (gTextures, i)];
}

do_dialog (id, "\n\nclick Ignore when done)", buttons);
}

do_dialog (key id, string msg, list buttons)
{
llListenRemove (gListenHandle);
gListenChannel = getRandomChannel();
gListenHandle = llListen (gListenChannel, "", id, "");
llSetTimerEvent (LISTEN_TIMEOUT);
llDialog (id, msg, buttons, gListenChannel);
}

default
{
on_rez (integer start_param)
{
llResetScript();
}

state_entry()
{
if (read_textures_from_inventory())
{
// We have textures in the inventory and have read them
gNotecards = FALSE;
}
else if (read_textures_from_notecards())
{
// We have textures read in from a notecard by UUID
// (or will have pretty soon)
gNotecards = TRUE;
}
else
{
llOwnerSay ("Note: There are no textures or notecards in this prim ...");
}
gMenuPage = 0;
}

touch_start(integer total_number)
{
// Start menu system again. Note that I don't do anything special
// with several people trying to touch it at the same time - it will
// always overlap the processing of gMenuPage, but all that will
// happen is that peoples next/back might be a bit quirky for a while.
// Eventually, they will sort themselves out!
gMenuPage = 0;
show_dialog (llDetectedKey(0));
}

listen (integer channel, string name, key id, string msg)
{
if (channel == gListenChannel)
{
if (msg == MENU_BACK)
{
gMenuPage--;
show_dialog (id);
}
else if (msg == MENU_TOP)
{
gMenuPage = 0;
show_dialog (id);
}
else if (msg == MENU_NEXT)
{
gMenuPage++;
show_dialog (id);
}
else if (msg == MENU_DEL)
{
llRemoveInventory(llGetScriptName());
}
else
{
// should be something in the inventory to give out
apply_texture (msg);

// reshow the dialog
if (gReshow)
{
show_dialog(id);
}
}
}
}

timer ()
{
// First see if we are timing out on a listen event
if (gListenHandle != 0)
{
// Remove the old listen
llListenRemove (gListenHandle);
gListenHandle = 0;
gListenChannel = 0;
}
}

dataserver(key query_id, string line)
{
if (query_id == gQueryID)
{
if (line != EOF)
{
if (llSubStringIndex (line, "=") != 0)
{
list vals = llParseString2List (line, ["="], []);

// Only store the first 24 characters of the name as this is all we can
// show in a dialog anyway
string texture = llList2String (vals, 0);
string uuid = llList2Key (vals, 1);
gTextures += [llGetSubString (texture, 0, 23)];
gTextureUUIDs += uuid;
doDebug ("Adding: " + texture + " ("+uuid+")");
}

// Now get the next line
gNotecardLine++;
gQueryID = llGetNotecardLine(gNotecardName, gNotecardLine);
}
else
{
gNumTextures = llGetListLength (gTextures);
doDebug ("Found " + (string)gNumTextures + " textures.");
}
}
}

changed (integer change)
{
if (change & CHANGED_INVENTORY)
{
llResetScript();
}
}
}
Ca marche nikel.

et serait-il possible d'avoir un sous menu comme dans ce resizer avec le choix de delete ou cancel ? Pour ceux qui clic trop vite hihi

Merci


Citation :
float MIN_DIMENSION=0.01; // the minimum scale of a prim allowed, in any dimension
float MAX_DIMENSION=10.0; // the maximum scale of a prim allowed, in any dimension

float max_scale;
float min_scale;

float cur_scale = 1.0;
integer handle;
integer menuChan;

float min_original_scale=10.0; // minimum x/y/z component of the scales in the linkset
float max_original_scale=0.0; // minimum x/y/z component of the scales in the linkset

list link_scales = [];
list link_positions = [];

makeMenu()
{
llListenRemove(handle);
menuChan = 50000 + (integer)llFrand(50000.00);
handle = llListen(menuChan,"",llGetOwner(),"");

//the button values can be changed i.e. you can set a value like "-1.00" or "+2.00"
//and it will work without changing anything else in the script
llDialog(llGetOwner(),"Max scale: "+(string)max_scale+"\nMin scale: "+(string)min_scale+"\n \nCurrent scale: "+
(string)cur_scale,["-0.05","-0.10","-0.25","+0.05","+0.10","+0.25","MIN SIZE","RESTORE","MAX SIZE","DELETE..."],menuChan);
}

integer scanLinkset()
{
integer link_qty = llGetNumberOfPrims();
integer link_idx;
vector link_pos;
vector link_scale;

//script made specifically for linksets, not for single prims
if (link_qty > 1)
{
//link numbering in linksets starts with 1
for (link_idx=1; link_idx <= link_qty; link_idx++)
{
link_pos=llList2Vector(llGetLinkPrimitiveParams(link_idx,[PRIM_POSITION]),0);
link_scale=llList2Vector(llGetLinkPrimitiveParams(link_idx,[PRIM_SIZE]),0);

// determine the minimum and maximum prim scales in the linkset,
// so that rescaling doesn't fail due to prim scale limitations
if(link_scale.x<min_original_scale) min_original_scale=link_scale.x;
else if(link_scale.x>max_original_scale) max_original_scale=link_scale.x;
if(link_scale.y<min_original_scale) min_original_scale=link_scale.y;
else if(link_scale.y>max_original_scale) max_original_scale=link_scale.y;
if(link_scale.z<min_original_scale) min_original_scale=link_scale.z;
else if(link_scale.z>max_original_scale) max_original_scale=link_scale.z;

link_scales += [link_scale];
link_positions += [(link_pos-llGetRootPosition())/llGetRootRotation()];
}
}
else
{
llOwnerSay("error: this script doesn't work for non-linked objects");
return FALSE;
}

max_scale = MAX_DIMENSION/max_original_scale;
min_scale = MIN_DIMENSION/min_original_scale;

return TRUE;
}

resizeObject(float scale)
{
integer link_qty = llGetNumberOfPrims();
integer link_idx;
vector new_size;
vector new_pos;

if (link_qty > 1)
{
//link numbering in linksets starts with 1
for (link_idx=1; link_idx <= link_qty; link_idx++)
{
new_size = scale * llList2Vector(link_scales, link_idx-1);
new_pos = scale * llList2Vector(link_positions, link_idx-1);

if (link_idx == 1)
{
//because we don't really want to move the root prim as it moves the whole object
llSetLinkPrimitiveParamsFast(link_idx, [PRIM_SIZE, new_size]);
}
else
{
llSetLinkPrimitiveParamsFast(link_idx, [PRIM_SIZE, new_size, PRIM_POSITION, new_pos]);
}
}
}
}

default
{
state_entry()
{
if (scanLinkset())
{
//llOwnerSay("resizer script ready");
}
else
{
llRemoveInventory(llGetScriptName());
}
}

touch_start(integer total)
{
if (llDetectedKey(0) == llGetOwner()) makeMenu();
}

listen(integer channel, string name, key id, string msg)
{
//you can never be too secure
if (id == llGetOwner())
{
if (msg == "RESTORE")
{
cur_scale = 1.0;
}
else if (msg == "MIN SIZE")
{
cur_scale = min_scale;
}
else if (msg == "MAX SIZE")
{
cur_scale = max_scale;
}
else if (msg == "DELETE...")
{
llDialog(llGetOwner(),"Are you sure you want to delete the resizer script?",
["DELETE","CANCEL"],menuChan);
return;
}
else if (msg == "DELETE")
{
llOwnerSay("deleting resizer script...");
llRemoveInventory(llGetScriptName());
}
else
{
cur_scale += (float)msg;
}

//check that the scale doesn't go beyond the bounds
if (cur_scale > max_scale) { cur_scale = max_scale; }
if (cur_scale < min_scale) { cur_scale = min_scale; }

resizeObject(cur_scale);
}
}
}

Dernière modification par skanajo ; 23/11/2019 à 01h47.
On peut tout...





integer gReshow = FALSE;
integer gSetTexture = FALSE; // Use SetTexture method (needed for textures not in the prim inventory)
integer gNotecards = FALSE; // Get textures to use from a notecard not inventory
integer gPreserveTextures = FALSE; // Read offset/rotation values from existing texture

// configures how textures appear
integer gFace = ALL_SIDES;
vector gRepeats = <1.0, 1.0, 1.0>;
vector gOffsets = <1.0, 1.0, 1.0>;
float gRotationInDegrees = 0.0;

// Do not change anything below this line (unless you know what you are doing)
integer gDebug = FALSE;
integer gMenuPage;
integer gNumTextures;
list gTextures;
list gTextureUUIDs;

string gNotecardName;
integer gNotecardLine = 0;
key gQueryID;

integer gListenChannel;
integer gListenHandle;

integer gListenHandle2;
integer canal2;

float gListenTimer;
float LISTEN_TIMEOUT=60.0;

string MENU_NEXT="Next>";
string MENU_TOP="Top";
string MENU_BACK="<Back";
string MENU_SPACE=" ";
string MENU_DEL="Del. Script";

string MENU_CANCEL="Cancel";
string MENU_DEL2 ="YES! I'M SURE!";

doDebug (string msg)
{
if (gDebug)
{
llOwnerSay (msg);
}
}

integer getRandomChannel ()
{
integer pos_int = (((integer)llFrand(16384)) << 17) | 65536 | ((integer)llFrand(65535));
return -pos_int;
}

integer read_textures_from_inventory ()
{
gNumTextures = llGetInventoryNumber (INVENTORY_TEXTURE);
gTextures = [];

integer i;
for (i=0; i<gNumTextures; i++)
{
string texture = llGetInventoryName (INVENTORY_TEXTURE, i);
// Only store the first 24 characters of the name as this is all we can
// show in a dialog anyway
gTextures += [llGetSubString (texture, 0, 23)];
doDebug ("read_textures: adding texture: " + texture);
}

return gNumTextures;
}

integer read_textures_from_notecards ()
{
// Read texture information from the first notecard in inventory
gNotecardName = llGetInventoryName(INVENTORY_NOTECARD, 0);
if (gNotecardName == "")
{
return FALSE;
}
else
{
gQueryID = llGetNotecardLine(gNotecardName, gNotecardLine);
return TRUE;
}
}

set_texture (string texture)
{
if (gSetTexture)
{
llSetTexture (texture, gFace);
}
else if (gPreserveTextures && gFace != ALL_SIDES)
{
// returns: [string texture, vector scale, vector offset, float rotation]
list scale_offset_rot = llGetPrimitiveParams ([PRIM_TEXTURE, gFace]);

llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_TEXTURE,
gFace,
texture,
llList2Vector (scale_offset_rot, 1),
llList2Vector (scale_offset_rot, 2),
llList2Float (scale_offset_rot, 3)]
);
}
else
{
llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_TEXTURE,
gFace,
texture,
gRepeats,
gOffsets,
gRotationInDegrees*DEG_TO_RAD]
);
}
}

apply_texture (string texture)
{
integer idx = llListFindList (gTextures, [texture]);
if (idx == -1)
{
// Didn't find it in the list - might not be a texture
return;
}

// Now need to find the texture that matches from the inventory
// and give it out
integer i;
for (i=0; i<gNumTextures ; i++)
{
if (gNotecards)
{
string texture_uuid = llList2Key (gTextureUUIDs, idx);
if (texture_uuid != "")
{
doDebug ("apply_texture: applying texture: " + texture_uuid);
set_texture (texture_uuid);
return;
}
}
else
{
string texture_full = llGetInventoryName(INVENTORY_TEXTURE, i);
if (llGetSubString (texture_full, 0, 23) == texture)
{
// This is the one
doDebug ("apply_texture: applying texture: " + texture_full);
set_texture (texture_full);
return;
}
}
}
}

show_dialog (key id)
{
list buttons = [MENU_DEL];

if (gNumTextures == 0)
{
do_dialog (id, "There are no textures to select at present.", []);
return;
}

// If several people are using the giver, then it is possible
// for gMenuPage to go negative or too high
if (gMenuPage < 0)
{
// Reset ...
gMenuPage = 0;
}
integer num_pages = ((gNumTextures+8)/9);
if (gMenuPage >= num_pages)
{
// gMenuPage is an index starting at 0...
// max is a 1...
gMenuPage = num_pages-1;
}

// Max buttons on a dialog is 12, so if more than that, then need to
// include special next/back button handling
integer first_texture = 0;
integer last_texture = gNumTextures-1;
if (gNumTextures > 12)
{
// Note: This yields notecards counting as follows:
// 0 to 8 = first page,
// 9 to 17 = next page, etc
first_texture = gMenuPage * 8;
last_texture = first_texture + 8 - 1;
if (last_texture >= gNumTextures)
{
// recall last_texture indexed from 0, but
// gNumTextures is indexed from 1
last_texture = gNumTextures-1;
}

if (gMenuPage > 0)
{
buttons += [MENU_BACK];
}
else
{
buttons += [MENU_SPACE];
}

if (gMenuPage == 0)
{
buttons += [MENU_SPACE];
//buttons += [MENU_DEL];
}
else
{
buttons += [MENU_TOP];
//buttons += [MENU_DEL];
}

// If not on the last page, and there are more pages to come ...
if (gNumTextures > 9 && gMenuPage < (num_pages-1))
{
buttons += [MENU_NEXT];
}
else
{
buttons += [MENU_SPACE];
}
}

integer i;
for (i=first_texture; (i <= last_texture) && (i < gNumTextures); i++)
{
buttons += [llList2String (gTextures, i)];
}

do_dialog (id, "\n\nclick Ignore when done)", buttons);
}

do_dialog (key id, string msg, list buttons)
{
llListenRemove (gListenHandle);
gListenChannel = getRandomChannel();
gListenHandle = llListen (gListenChannel, "", id, "");
llSetTimerEvent (LISTEN_TIMEOUT);
llDialog (id, msg, buttons, gListenChannel);
}

default
{
on_rez (integer start_param)
{
llResetScript();
}

state_entry()
{
if (read_textures_from_inventory())
{
// We have textures in the inventory and have read them
gNotecards = FALSE;
}
else if (read_textures_from_notecards())
{
// We have textures read in from a notecard by UUID
// (or will have pretty soon)
gNotecards = TRUE;
}
else
{
llOwnerSay ("Note: There are no textures or notecards in this prim ...");
}
gMenuPage = 0;
}

touch_start(integer total_number)
{
// Start menu system again. Note that I don't do anything special
// with several people trying to touch it at the same time - it will
// always overlap the processing of gMenuPage, but all that will
// happen is that peoples next/back might be a bit quirky for a while.
// Eventually, they will sort themselves out!
gMenuPage = 0;
show_dialog (llDetectedKey(0));
}

listen (integer channel, string name, key id, string msg)
{
if (channel == gListenChannel)
{
if (msg == MENU_BACK)
{
gMenuPage--;
show_dialog (id);
}
else if (msg == MENU_TOP)
{
gMenuPage = 0;
show_dialog (id);
}
else if (msg == MENU_NEXT)
{
gMenuPage++;
show_dialog (id);
}
else if (msg == MENU_DEL)
{
canal2 = -((integer)(llFrand(100000)+100000));
gListenHandle2 = llListen (canal2, "", id, "");;
llDialog(id,"Are you really sure you want to delete this script?",
[MENU_DEL2,MENU_CANCEL],canal2);
return;
}
else
{
// should be something in the inventory to give out
apply_texture (msg);

// reshow the dialog
if (gReshow)
{
show_dialog(id);
}
}
}

else if(channel == canal2)
{
if( msg == MENU_DEL2)
{
llOwnerSay("deleting script...");
llRemoveInventory(llGetScriptName());
}
}
}

timer ()
{
// First see if we are timing out on a listen event
if (gListenHandle != 0)
{
// Remove the old listen
llListenRemove (gListenHandle);
gListenHandle = 0;
gListenChannel = 0;
}
}

dataserver(key query_id, string line)
{
if (query_id == gQueryID)
{
if (line != EOF)
{
if (llSubStringIndex (line, "=") != 0)
{
list vals = llParseString2List (line, ["="], []);

// Only store the first 24 characters of the name as this is all we can
// show in a dialog anyway
string texture = llList2String (vals, 0);
string uuid = llList2Key (vals, 1);
gTextures += [llGetSubString (texture, 0, 23)];
gTextureUUIDs += uuid;
doDebug ("Adding: " + texture + " ("+uuid+")");
}

// Now get the next line
gNotecardLine++;
gQueryID = llGetNotecardLine(gNotecardName, gNotecardLine);
}
else
{
gNumTextures = llGetListLength (gTextures);
doDebug ("Found " + (string)gNumTextures + " textures.");
}
}
}

changed (integer change)
{
if (change & CHANGED_INVENTORY)
{
llResetScript();
}
}
}
Alors si on peut tout, je vais si tu le veux bien encore abuser de tes connaissances
si on pouvait faire un sous menu Textures et rajouter un sous menu Access (pour choisir owner, group ou public) ?
Merci Msieur
"faire un sous menu Textures et rajouter un sous menu Access"....gné ?? un sous menu d' un sous menu ??? je rappelle qd mm que le script de départ est très pénible...et pour l' instant on a rajouté du bricolage.....à force de sur rjouter du bricolage....ça va finir par être n' imp...
oui enfin ce que je voulais dire c'était un bouton delete, un bouton access, et un bouton textures qui nous envoi vers le choix de textures, mais en effet si c trop tordu laisse tomber. c'est déjà super comme ça, c'était pour faire plus abouti.
Bonjour,
j'ai tenté en partant des modifs du 1er script d'intégrer l'option delete à un autre script de changement de texture qui marche sans notecard (avec les uuid directement dans le script) et avec accès seulement pour le owner. Mais j'ai des erreurs de syntaxe. Normal je pense vu que j'essai de bricoler au vu de mes connaissances en programmation.
Je copie le nouveau script
Code PHP:

[php]string msg "Please make a choice.";
string msgTimeout "Sorry. Menu has timed out. Please try again.";
float Timeout60;

//Texture names
list TEXTURE_LIST = ["Texture 1""Texture 2""Texture 3"];
//Texture uuid's
list TEXTURE_VALUE = ["UUID1""UUID2""UUID3"];

integer channel_dialog;
integer listen_id;
key ToucherID
 
integer N_DIALOG_CHOICES;
integer MAX_DIALOG_CHOICES_PER_PG 9
string PREV_PG_DIALOG_PREFIX "< Page ";
string NEXT_PG_DIALOG_PREFIX "> Page ";
string SlideShowCurrent;
integer pageNum;
 
giveDialog(key IDinteger pageNum) {
    list 
buttons;
    
integer firstChoice;
    
integer lastChoice;
    
integer prevPage;
    
integer nextPage;
    
string OnePage;
    
N_DIALOG_CHOICES llGetListLength(TEXTURE_LIST);
    if (
N_DIALOG_CHOICES <= 10) {
        
buttons TEXTURE_LIST;
        
OnePage "Yes";
    }
    else {
        
integer nPages = (N_DIALOG_CHOICES+MAX_DIALOG_CHOICES_PER_PG-1)/MAX_DIALOG_CHOICES_PER_PG;
        if (
pageNum || pageNum nPages) {
            
pageNum 1;
        }
        
integer firstChoice = (pageNum-1)*MAX_DIALOG_CHOICES_PER_PG;
        
integer lastChoice firstChoice+MAX_DIALOG_CHOICES_PER_PG-1;
        if (
lastChoice >= N_DIALOG_CHOICES) {
            
lastChoice N_DIALOG_CHOICES;
        }
        if (
pageNum <= 1) {
            
prevPage nPages;
            
nextPage 2;
        }
        else if (
pageNum >= nPages) {
            
prevPage nPages-1;
            
nextPage 1;
        }
        else {
            
prevPage pageNum-1;
            
nextPage pageNum+1;
        }
        
buttons llList2List(TEXTURE_LISTfirstChoicelastChoice);
    }
    
// FYI, this puts the navigation button row first, so it is always at the bottom of the dialog
        
list buttons01 llList2List(buttons02);
        list 
buttons02 llList2List(buttons35);
        list 
buttons03 llList2List(buttons68);
        list 
buttons04;
        if (
OnePage == "Yes") {
            
buttons04 llList2List(buttons911);
        }
        
buttons buttons04 buttons03 buttons02 buttons01;
        if (
OnePage == "Yes") {
            
buttons = []+ buttons;
            
        }
        else {
            
buttons =
            (
buttons=[])+
            [ 
PREV_PG_DIALOG_PREFIX+(string)prevPageNEXT_PG_DIALOG_PREFIX+(string)nextPage]+buttons;
                  }
        
llDialog(ID"Page "+(string)pageNum+"\nChoose one:"buttonschannel_dialog);
}
 
 
CancelListen() {
    
llListenRemove(listen_id);
    
llSetTimerEvent(0);
}
 
default{
  
state_entry() {
    
channel_dialog = ( -* (integer)("0x"+llGetSubString((string)llGetKey(),-5,-1)) );
  }
 
  
touch_start(integer total_number) {
    
ToucherID llDetectedKey(0);
    
listen_id llListenchannel_dialog""ToucherID"");
    
llSetTimerEvent(Timeout);
    
pageNum 1;

    if (
llDetectedKey(0) == llGetOwner())
        {
            
giveDialog(ToucherIDpageNum);
        }

        else
        {
            
llListenRemove(listen_id);
llSetTimerEvent(0.0);
        }
  }
 
 
  
listen(integer channelstring namekey idstring choice) {
    if (
choice == "-") {
    
giveDialog(ToucherIDpageNum); 
    }
    else if (
llSubStringIndex(choicePREV_PG_DIALOG_PREFIX) == 0){
        
pageNum =
        (integer)
llGetSubString(choicellStringLength(PREV_PG_DIALOG_PREFIX), -1);
        
giveDialog(ToucherIDpageNum);
    }
    else if (
llSubStringIndex(choiceNEXT_PG_DIALOG_PREFIX) == 0) {
        
pageNum =
        (integer)
llGetSubString(choicellStringLength(NEXT_PG_DIALOG_PREFIX), -1);
        
giveDialog(ToucherIDpageNum);
    }
else { 
    
        
integer i llListFindList(TEXTURE_LIST, [choice]);
string texture llList2String(TEXTURE_VALUEi);

llSetTexture(texture,ALL_SIDES);
llListenRemove(listen_id);
llSetTimerEvent(0.0);

 
    }
  }
 
  
timer() {
    
llListenRemove(listen_id);
llOwnerSay(msgTimeout);
llSetTimerEvent(0.0);
  }

[/php]

Voici ce que j'ai tenté (on ne se moque pas)


Code PHP:

&#8203;string msg = "Please make a choice.";
string msgTimeout "Sorry. Menu has timed out. Please try again.";
float Timeout60;

//Texture names
list TEXTURE_LIST = ["Texture 1""Texture 2""Texture 3"];
//Texture uuid's
list TEXTURE_VALUE = ["UUID1""UUID2""UUID3"];

integer channel_dialog;
integer listen_id;
key ToucherID

integer glistenHandle2;
integer canal2;
 
integer N_DIALOG_CHOICES;
integer MAX_DIALOG_CHOICES_PER_PG 9

string MENU_DEL="Del. Script";

string MENU_CANCEL="Cancel";
string MENU_DEL2 ="YES! I'M SURE!";

string PREV_PG_DIALOG_PREFIX "< Page ";
string NEXT_PG_DIALOG_PREFIX "> Page ";
string SlideShowCurrent;
integer pageNum;
 
giveDialog(key IDinteger pageNum) {
    list 
buttons;
    
integer firstChoice;
    
integer lastChoice;
    
integer prevPage;
    
integer nextPage;
    
string OnePage;
    
N_DIALOG_CHOICES llGetListLength(TEXTURE_LIST);
    if (
N_DIALOG_CHOICES <= 10) {
        
buttons TEXTURE_LIST;
        
OnePage "Yes";
    }
    else {
        
integer nPages = (N_DIALOG_CHOICES+MAX_DIALOG_CHOICES_PER_PG-1)/MAX_DIALOG_CHOICES_PER_PG;
        if (
pageNum || pageNum nPages) {
            
pageNum 1;
        }
        
integer firstChoice = (pageNum-1)*MAX_DIALOG_CHOICES_PER_PG;
        
integer lastChoice firstChoice+MAX_DIALOG_CHOICES_PER_PG-1;
        if (
lastChoice >= N_DIALOG_CHOICES) {
            
lastChoice N_DIALOG_CHOICES;
        }
        if (
pageNum <= 1) {
            
prevPage nPages;
            
nextPage 2;
        }
        else if (
pageNum >= nPages) {
            
prevPage nPages-1;
            
nextPage 1;
        }
        else {
            
prevPage pageNum-1;
            
nextPage pageNum+1;
        }
        
buttons llList2List(TEXTURE_LISTfirstChoicelastChoice);
    }
    
// FYI, this puts the navigation button row first, so it is always at the bottom of the dialog
        
list buttons01 llList2List(buttons02);
        list 
buttons02 llList2List(buttons35);
        list 
buttons03 llList2List(buttons68);
        list 
buttons04;
        if (
OnePage == "Yes") {
            
buttons04 llList2List(buttons911);
    
//buttons += [MENU_DEL];
        
}
        
buttons buttons04 buttons03 buttons02 buttons01;
        if (
OnePage == "Yes") {
             
buttons = []+ buttons;
    
//buttons += [MENU_DEL];
             
        
}
        else {
            
buttons =
            (
buttons=[])+
            [ 
PREV_PG_DIALOG_PREFIX+(string)prevPageNEXT_PG_DIALOG_PREFIX+(string)nextPage]+buttons;
                   }
        
llDialog(ID"Page "+(string)pageNum+"\nChoose one:"buttonschannel_dialog);
}
 
 
CancelListen() {
    
llListenRemove(listen_id);
    
llSetTimerEvent(0);
}
 
default{
  
state_entry() {
    
channel_dialog = ( -* (integer)("0x"+llGetSubString((string)llGetKey(),-5,-1)) );
  }
 
  
touch_start(integer total_number) {
    
ToucherID llDetectedKey(0);
    
listen_id llListenchannel_dialog""ToucherID"");
    
llSetTimerEvent(Timeout);
    
pageNum 1;

    if (
llDetectedKey(0) == llGetOwner())
        {
            
giveDialog(ToucherIDpageNum);
        }

        else
        {
            
llListenRemove(listen_id);
llSetTimerEvent(0.0);
        }
  }
 
 
  
listen(integer channelstring namekey idstring choice) {
    if (
choice == "-") {
     
giveDialog(ToucherIDpageNum); 
    }
    else if (
llSubStringIndex(choicePREV_PG_DIALOG_PREFIX) == 0){
        
pageNum =
        (integer)
llGetSubString(choicellStringLength(PREV_PG_DIALOG_PREFIX), -1);
        
giveDialog(ToucherIDpageNum);
    }
    else if (
llSubStringIndex(choiceNEXT_PG_DIALOG_PREFIX) == 0) {
        
pageNum =
        (integer)
llGetSubString(choicellStringLength(NEXT_PG_DIALOG_PREFIX), -1);
        
giveDialog(ToucherIDpageNum);
    }
else if (
msg == MENU_DEL)
{
canal2 = -((integer)(llFrand(100000)+100000));
gListenHandle2 llListen (canal2""id"");;
llDialog(id,"Are you really sure you want to delete this script?",
[
MENU_DEL2,MENU_CANCEL],canal2);
return;
}
else 

if (
gReshow)
{
show_dialog(id);
}
}
}

else if(
channel == canal2)
{
if( 
msg == MENU_DEL2)
{
llOwnerSay("deleting script...");
llRemoveInventory(llGetScriptName());
}
}
    
        
integer i llListFindList(TEXTURE_LIST, [choice]);
string texture llList2String(TEXTURE_VALUEi);

llSetTexture(texture,ALL_SIDES);
llListenRemove(listen_id);
llSetTimerEvent(0.0);
}

}
 
 
timer() 
  {
    
llListenRemove(listen_id);
llOwnerSay(msgTimeout);
llSetTimerEvent(0.0);
  }


Dernière modification par skanajo ; 26/11/2019 à 14h28. Motif: Auto-fusion
Code PHP:

list textures = [
  
"Texture 1",
  
"Texture 2",
  
"Texture 3",
  
"Texture 4",
  
"Texture 5",
  
"Texture 6",
  
"Texture 7",
  
"Texture 8",
  
"Texture 9",
  
"Texture 10",
  
"Texture 11",
  
"Texture 12",
  
"Texture 13",
  
"Texture 14",
  
"Texture 15"];

list 
cles = [
    
"6f45d638-5b06-aeeb-b17c-9da2a4664b20",
    
"bb7fdc52-0aef-7bed-5460-6022851f523b",
    
"76954608-0f5c-5f50-daec-83ffe54f097a",
    
"48ac9dd6-90b5-01a4-01da-d14f5871a080",
    
"53ab110d-6f2a-443a-0fcb-b1fefef3d951",
    
"61e416e5-2e26-dd1c-5b20-c86cb425d322",
    
"ddafa27e-d3e7-cdb4-7691-4646b31166f0",
    
"da2a99f0-9bf5-aec1-f50f-f24f4bfa5979",
    
"3d9b86e6-0d00-c9a1-2a58-48e5d95035ea",
    
"6a924c0c-9152-1e20-c3f8-48fbafaa5734",
    
"90799d10-6bd6-6861-13d1-cf1945a11cd5",
    
"77e644f9-00b5-cfe7-51f8-dfdc08cbac1b",
    
"2000195a-0db1-1f09-80c7-91e92ad87659",
    
"3ad8362b-1fe8-f84e-11b6-438f3c755c8e",
    
"3d804f0b-ff1b-7c6a-cf3f-b6fa0748ed12"];
    
    
/////////////////////////////////////////////////////
    //////les clés doivent evidement correspondre à la place de leur texture ds la liste des textures///////    
    //////////////////////////////////////////////////

list ListeBoutons;

integer canal1;
integer canal2;
integer menuindex;
integer listen_handle1;
integer listen_handle2;

key owner


list 
order_buttons(list buttons)
{
    return 
llList2List(buttons, -3, -1) + llList2List(buttons, -6, -4) +
          
llList2List(buttons, -9, -7) + llList2List(buttons, -12, -10);
}

DialogPlus(key avatarstring message, list buttonsinteger channelinteger CurMenu)
{
  if (
12 llGetListLength(buttons))
    {
        list 
lbut buttons;
        list 
Nbuttons = [];
        if(
CurMenu == -1)
        {
            
CurMenu 0;
            
menuindex 0;
        }
 
        if((
Nbuttons = (llList2List(buttons, (CurMenu 9), ((CurMenu 9) + 8)) + ["<<<","Suppr script"">>>"])) == ["<<<","Suppr script"">>>"])
            
DialogPlus(avatarmessagelbutchannelmenuindex 0);
        else
            
llDialog(avatarmessage,  order_buttons(Nbuttons), channel);
    }
    else
        
llDialog(avatarmessage,  order_buttons(buttons+["Suppr script"]), channel);
}


default
{
 
state_entry()
    {
      
owner llGetOwner();
      
canal1 = (integer)("0xA" llGetSubString((string)llGetKey(), 0,));
      
canal2 = -1*(integer)("0xA" llGetSubString((string)llGetKey(), 0,)); 
      
      
llOwnerSay((string)llGetFreeMemory() + " bytes de memoire libre.\n"
        
+(string)llGetListLength(textures)+ " textures listées ");
    }
    
 
touch_start(integer total_number)
    {        
    if(
owner==llDetectedKey(0))
      {          
        
ListeBoutons = [];
        
integer i;
        
integer a llGetListLength(textures);
 
        do
        {
          
ListeBoutons += llGetSubString(llList2String(texturesi),0,12);
        }
        while (++
a); 

        
listen_handle1 llListen(canal1""owner,"");
        
llSetTimerEvent(30.0);
        
DialogPlus(owner"Choise une texture"ListeBoutonscanal1menuindex 0);
      }
    }
    
    
 
listen(integer chanstring namekey idstring msg)
    {
    if(
chan == canal1)
    {
        if(
msg == ">>>")
        {
            
DialogPlus(owner,  "Choise une texture"ListeBoutonscanal1, ++menuindex);
        }

        else if(
msg == "<<<")
        {
            
DialogPlus(owner,  "Choise une texture"ListeBoutonscanal1, --menuindex);
        }
        
        else if (
msg == "Suppr script")
        {
        
listen_handle2  llListen (canal2""owner"");;
        
llDialog(owner,"Are you really sure you want to delete this script?",
        [
"Sur à fond!","plus tard"],canal2);
        return;
        }

        else
        {
            
llListenRemove(listen_handle1);
            
llSetTimerEvent(0.0);
            
            
integer index llListFindList(ListeBoutons, [msg]);
            
string texture llList2String(texturesindex);
            
key cle llList2Key(clesindex);
            
            
llOwnerSay(texture);
            
            
llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_TEXTURE,
            
ALL_SIDES,//face
            
cle,//texture
            
<1.01.0FALSE>,//repet
            
<1.01.0FALSE>,//decalage
            
0.0//rotation en degrés
            
]);
        }
    }
        
    else if(
chan == canal2)
    {    
    if( 
msg == "Sur à fond!")
      {
    
llOwnerSay("byebye  script...");
    
llRemoveInventory(llGetScriptName());
      }
   else
      {
       
llListenRemove(listen_handle2);
      }
    }
}
        
 
timer()
    {
        
llOwnerSay("Temps ecoulé.");
        
llListenRemove(listen_handle1);
        
llSetTimerEvent(0.0);
    }
    
 
changed(integer change)
    {
        if (
change & (CHANGED_OWNER CHANGED_INVENTORY)) 
        {
            
llOwnerSay("Le proprio ou le script a changé ");
            
llResetScript();
        }
    }
    
 
on_rez(integer start_param)
  {
      
llResetScript(); 
  }


Dernière modification par MenthalOH ; 28/11/2019 à 20h53.
merci, j'ai du rater cette ligne, je cherchais justement la valeur 12 quelques part j'ai du aller trop vite. merci beaucoup

j'ai testé avec une valeur de 15, 18 et 24, ça me limite à 14 ou 15 caractères selon les boutons, je me demande aussi si les chiffres ou certaines lettres ne comptent pas plus qu'1 caractère au final

Dernière modification par skanajo ; 29/11/2019 à 15h30. Motif: Auto-fusion
Répondre

Connectés sur ce fil

 
1 connecté (0 membre et 1 invité) Afficher la liste détaillée des connectés